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    }