001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.gbean;
019
020 import java.io.IOException;
021 import java.io.ObjectInputStream;
022 import java.io.Serializable;
023 import java.lang.reflect.Method;
024 import java.util.ArrayList;
025 import java.util.Arrays;
026 import java.util.Collection;
027 import java.util.Collections;
028 import java.util.HashMap;
029 import java.util.HashSet;
030 import java.util.Iterator;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.Set;
034
035 import org.apache.geronimo.kernel.management.NotificationType;
036
037 /**
038 * Describes a GBean. This class should never be constructed directly. Insted use GBeanInfoBuilder.
039 *
040 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
041 */
042 public final class GBeanInfo implements Serializable {
043 private static final long serialVersionUID = -6198804067155550221L;
044
045 public static final int PRIORITY_CLASSLOADER = 1;
046 public static final int PRIORITY_NORMAL = 5;
047
048 private static final Set DEFAULT_NOTIFICATIONS = Collections.unmodifiableSet(new HashSet(Arrays.asList(NotificationType.TYPES)));
049
050 /**
051 * Static helper to try to get the GBeanInfo from the class supplied.
052 *
053 * @param className name of the class to get the GBeanInfo from
054 * @param classLoader the class loader use to load the specifiec class
055 * @return GBeanInfo generated by supplied class
056 * @throws InvalidConfigurationException
057 * if there is a problem getting the GBeanInfo from the class
058 */
059 public static GBeanInfo getGBeanInfo(String className, ClassLoader classLoader) throws InvalidConfigurationException {
060 Class clazz;
061 try {
062 clazz = classLoader.loadClass(className);
063 } catch (ClassNotFoundException e) {
064 throw new InvalidConfigurationException("Could not load class " + className, e);
065 } catch (NoClassDefFoundError e) {
066 throw new InvalidConfigurationException("Could not load class " + className, e);
067 }
068 Method method;
069 try {
070 method = clazz.getDeclaredMethod("getGBeanInfo", new Class[]{});
071 } catch (NoSuchMethodException e) {
072 try {
073 // try to get the info from ${className}GBean
074 clazz = classLoader.loadClass(className + "GBean");
075 method = clazz.getDeclaredMethod("getGBeanInfo", new Class[]{});
076 } catch (Exception ignored) {
077 throw new InvalidConfigurationException("Class does not have a getGBeanInfo() method: " + className);
078 }
079 } catch (NoClassDefFoundError e) {
080 String message = e.getMessage();
081 StringBuffer buf = new StringBuffer("Could not load gbean class ").append(className).append(" due to NoClassDefFoundError\n");
082 if (message != null) {
083 message = message.replace('/', '.');
084 buf.append(" problematic class ").append(message);
085 try {
086 Class hardToLoad = classLoader.loadClass(message);
087 buf.append(" can be loaded in supplied classloader ").append(classLoader).append("\n");
088 buf.append(" and is found in ").append(hardToLoad.getClassLoader());
089 } catch (ClassNotFoundException e1) {
090 buf.append(" cannot be loaded in supplied classloader ").append(classLoader).append("\n");
091 }
092 }
093 throw new InvalidConfigurationException(buf.toString(), e);
094 }
095 try {
096 return (GBeanInfo) method.invoke(null, new Object[]{});
097 } catch (Exception e) {
098 throw new InvalidConfigurationException("Could not get GBeanInfo from class: " + className, e);
099 }
100 }
101
102 private final String sourceClass;
103 private final String name;
104 private final String className;
105 private final String j2eeType;
106 private final Set<GAttributeInfo> attributes;
107 private final Map attributesByName;
108 private final GConstructorInfo constructor;
109 private final Set operations;
110 private final Set notifications;
111 private final Set references;
112 private final Map referencesByName;
113 private final Set interfaces;
114 private int priority;
115
116 /**
117 * @deprecated use GBeanInfoBuilder
118 */
119 public GBeanInfo(String name, String className, String j2eeType, Collection attributes, GConstructorInfo constructor, Collection operations, Set references, Set interfaces) {
120 this(null, name, className, j2eeType, attributes, constructor, operations, references, interfaces, DEFAULT_NOTIFICATIONS, PRIORITY_NORMAL);
121 }
122
123 /**
124 * @deprecated use GBeanInfoBuilder
125 */
126 public GBeanInfo(String className, String j2eeType, Collection attributes, GConstructorInfo constructor, Collection operations, Set references, Set interfaces) {
127 this(null, className, className, j2eeType, attributes, constructor, operations, references, interfaces, DEFAULT_NOTIFICATIONS, PRIORITY_NORMAL);
128 }
129
130 /**
131 * @deprecated use GBeanInfoBuilder
132 */
133 public GBeanInfo(String className, String j2eeType, Collection attributes, GConstructorInfo constructor, Collection operations, Set references, Set interfaces, Set notifications) {
134 this(null, className, className, j2eeType, attributes, constructor, operations, references, interfaces, notifications, PRIORITY_NORMAL);
135 }
136
137 /**
138 * @deprecated use GBeanInfoBuilder
139 */
140 public GBeanInfo(String name, String className, String j2eeType, Collection attributes, GConstructorInfo constructor, Collection operations, Set references, Set interfaces, Set notifications) {
141 this(null, name, className, j2eeType, attributes, constructor, operations, references, interfaces, notifications, PRIORITY_NORMAL);
142 }
143
144 GBeanInfo(String sourceClass, String name, String className, String j2eeType, Collection attributes, GConstructorInfo constructor, Collection operations, Set references, Set interfaces, int priority) {
145 this(sourceClass, name, className, j2eeType, attributes, constructor, operations, references, interfaces, DEFAULT_NOTIFICATIONS, priority);
146 }
147
148 GBeanInfo(String sourceClass, String name, String className, String j2eeType, Collection attributes, GConstructorInfo constructor, Collection operations, Set references, Set interfaces, Set notifications, int priority) {
149 this.sourceClass = sourceClass;
150 this.name = name;
151 this.className = className;
152 this.j2eeType = j2eeType;
153 if (attributes == null) {
154 this.attributes = Collections.EMPTY_SET;
155 this.attributesByName = Collections.EMPTY_MAP;
156 } else {
157 Map map = new HashMap();
158 for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
159 GAttributeInfo attribute = (GAttributeInfo) iterator.next();
160 map.put(attribute.getName(), attribute);
161 }
162 this.attributesByName = Collections.unmodifiableMap(map);
163 this.attributes = Collections.unmodifiableSet(new HashSet(map.values()));
164 }
165 if (constructor == null) {
166 this.constructor = new GConstructorInfo(Collections.EMPTY_LIST);
167 } else {
168 this.constructor = constructor;
169 }
170 if (operations == null) {
171 this.operations = Collections.EMPTY_SET;
172 } else {
173 this.operations = Collections.unmodifiableSet(new HashSet(operations));
174 }
175 if (references == null) {
176 this.references = Collections.EMPTY_SET;
177 this.referencesByName = Collections.EMPTY_MAP;
178 } else {
179 Map map = new HashMap();
180 for (Iterator iterator = references.iterator(); iterator.hasNext();) {
181 GReferenceInfo reference = (GReferenceInfo) iterator.next();
182 map.put(reference.getName(), reference);
183 }
184 this.referencesByName = Collections.unmodifiableMap(map);
185 this.references = Collections.unmodifiableSet(new HashSet(references));
186 }
187 if (interfaces == null) {
188 this.interfaces = Collections.EMPTY_SET;
189 } else {
190 this.interfaces = Collections.unmodifiableSet(new HashSet(interfaces));
191 }
192 if (notifications == null) {
193 this.notifications = Collections.EMPTY_SET;
194 } else {
195 this.notifications = Collections.unmodifiableSet(new HashSet(notifications));
196 }
197 this.priority = priority;
198 }
199
200 /**
201 * Gets the source class from which this GBeanInfo can be retrieved using GBeanInfo.getGBeanInfo(className, classLoader).
202 * A null source class means the gbean info was dynamically generated.
203 *
204 * @return the source of this GBeanInfo, or null if it was dynamically generated
205 */
206 public String getSourceClass() {
207 return sourceClass;
208 }
209
210 public String getName() {
211 return name;
212 }
213
214 public String getClassName() {
215 return className;
216 }
217
218 public String getJ2eeType() {
219 return j2eeType;
220 }
221
222 /**
223 * Gets the info for the specified attribute, or null if there is no such
224 * attribute. Note that the attribute may have a getter or setter or both;
225 * being an attribute does not imply that both methods are available.
226 */
227 public GAttributeInfo getAttribute(String name) {
228 return (GAttributeInfo) attributesByName.get(name);
229 }
230
231 /**
232 * Returns a Set where the elements are type GAttributeInfo
233 */
234 public Set<GAttributeInfo> getAttributes() {
235 return attributes;
236 }
237
238 /**
239 * Returns a list where the elements are type GAttributeInfo
240 */
241 public List getPersistentAttributes() {
242 List attrs = new ArrayList();
243 for (Iterator i = attributes.iterator(); i.hasNext();) {
244 GAttributeInfo info = (GAttributeInfo) i.next();
245 if (info.isPersistent()) {
246 attrs.add(info);
247 }
248 }
249 return attrs;
250 }
251
252 /**
253 * Returns a list where the elements are type GAttributeInfo
254 */
255 public List getManageableAttributes() {
256 List attrs = new ArrayList();
257 for (Iterator i = attributes.iterator(); i.hasNext();) {
258 GAttributeInfo info = (GAttributeInfo) i.next();
259 if (info.isManageable()) {
260 attrs.add(info);
261 }
262 }
263 return attrs;
264 }
265
266 public GConstructorInfo getConstructor() {
267 return constructor;
268 }
269
270 public Set getOperations() {
271 return operations;
272 }
273
274 public Set getNotifications() {
275 return notifications;
276 }
277
278 public Set getReferences() {
279 return references;
280 }
281
282 public GReferenceInfo getReference(String name) {
283 return (GReferenceInfo) referencesByName.get(name);
284 }
285
286 public Set getInterfaces() {
287 return interfaces;
288 }
289
290 public int getPriority() {
291 return priority;
292 }
293
294 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
295 priority = GBeanInfo.PRIORITY_NORMAL;
296 in.defaultReadObject();
297 }
298
299 public String toString() {
300 StringBuffer result = new StringBuffer("[GBeanInfo:");
301 result.append(" id=").append(super.toString());
302 result.append(" sourceClass=").append(sourceClass);
303 result.append(" name=").append(name);
304 for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
305 GAttributeInfo geronimoAttributeInfo = (GAttributeInfo) iterator.next();
306 result.append("\n attribute: ").append(geronimoAttributeInfo);
307 }
308 for (Iterator iterator = operations.iterator(); iterator.hasNext();) {
309 GOperationInfo geronimoOperationInfo = (GOperationInfo) iterator.next();
310 result.append("\n operation: ").append(geronimoOperationInfo);
311 }
312 for (Iterator iterator = references.iterator(); iterator.hasNext();) {
313 GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
314 result.append("\n reference: ").append(referenceInfo);
315 }
316 result.append("]");
317 return result.toString();
318 }
319
320 public String toXML(AbstractName abstractName) {
321 StringBuilder xml = new StringBuilder();
322
323 xml.append("<gBeanInfo ");
324 xml.append("id='" + super.toString() + "' ");
325 xml.append("sourceClass='" + sourceClass + "' ");
326 xml.append("name='" + name + "' ");
327 xml.append("className='" + className + "' ");
328 xml.append("type='" + j2eeType + "' ");
329 xml.append("priority='" + priority + "' ");
330 xml.append(">");
331
332 xml.append("<attributes>");
333
334 for (Iterator loop = attributes.iterator(); loop.hasNext(); ) {
335 xml.append(((GAttributeInfo) loop.next()).toXML(abstractName));
336 }
337
338 xml.append("</attributes>");
339
340 xml.append(constructor.toXML());
341
342 xml.append("<operations>");
343
344 for (Iterator loop = operations.iterator(); loop.hasNext(); ) {
345 xml.append(((GOperationInfo) loop.next()).toXML());
346 }
347
348 xml.append("</operations>");
349
350 xml.append("<notifications>");
351
352 // I had expected this to be a set of GNotification Objects
353 // but it was just strings
354 for (Iterator loop = notifications.iterator(); loop.hasNext(); ) {
355 Object note = loop.next();
356
357 xml.append("<notification>" + note + "</notification>");
358 }
359
360 xml.append("</notifications>");
361
362 xml.append("<references>");
363
364 for (Iterator loop = references.iterator(); loop.hasNext(); ) {
365 xml.append(((GReferenceInfo) loop.next()).toXML());
366 }
367
368 xml.append("</references>");
369
370 xml.append("</gBeanInfo>");
371
372 return xml.toString();
373 }
374 }