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.connector.deployment;
019
020 import java.lang.reflect.Field;
021 import java.lang.reflect.Method;
022 import java.util.HashMap;
023 import java.util.List;
024 import java.util.Map;
025
026 import javax.annotation.Resource;
027 import javax.naming.Reference;
028 import javax.xml.namespace.QName;
029
030 import org.apache.commons.logging.Log;
031 import org.apache.commons.logging.LogFactory;
032 import org.apache.geronimo.common.DeploymentException;
033 import org.apache.geronimo.common.UnresolvedReferenceException;
034 import org.apache.geronimo.gbean.AbstractNameQuery;
035 import org.apache.geronimo.gbean.GBeanInfo;
036 import org.apache.geronimo.gbean.GBeanInfoBuilder;
037 import org.apache.geronimo.j2ee.deployment.Module;
038 import org.apache.geronimo.j2ee.deployment.EARContext;
039 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedApp;
040 import org.apache.geronimo.j2ee.deployment.annotation.ResourceAnnotationHelper;
041 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
042 import org.apache.geronimo.kernel.GBeanNotFoundException;
043 import org.apache.geronimo.kernel.config.Configuration;
044 import org.apache.geronimo.kernel.repository.Environment;
045 import org.apache.geronimo.naming.deployment.AbstractNamingBuilder;
046 import org.apache.geronimo.naming.reference.ResourceReference;
047 import org.apache.geronimo.naming.reference.UserTransactionReference;
048 import org.apache.geronimo.xbeans.geronimo.naming.GerMessageDestinationDocument;
049 import org.apache.geronimo.xbeans.geronimo.naming.GerMessageDestinationType;
050 import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType;
051 import org.apache.geronimo.xbeans.geronimo.naming.GerResourceEnvRefDocument;
052 import org.apache.geronimo.xbeans.geronimo.naming.GerResourceEnvRefType;
053 import org.apache.geronimo.xbeans.javaee.DescriptionType;
054 import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType;
055 import org.apache.geronimo.xbeans.javaee.InjectionTargetType;
056 import org.apache.geronimo.xbeans.javaee.JndiNameType;
057 import org.apache.geronimo.xbeans.javaee.MessageDestinationRefType;
058 import org.apache.geronimo.xbeans.javaee.MessageDestinationType;
059 import org.apache.geronimo.xbeans.javaee.MessageDestinationTypeType;
060 import org.apache.geronimo.xbeans.javaee.ResourceEnvRefType;
061 import org.apache.geronimo.xbeans.javaee.XsdStringType;
062 import org.apache.xmlbeans.QNameSet;
063 import org.apache.xmlbeans.XmlObject;
064
065 /**
066 * @version $Rev: 547737 $ $Date: 2007-06-15 12:47:19 -0400 (Fri, 15 Jun 2007) $
067 */
068 public class AdminObjectRefBuilder extends AbstractNamingBuilder {
069 private final static Log log = LogFactory.getLog(AdminObjectRefBuilder.class);
070 private final QNameSet adminOjbectRefQNameSet;
071 private final QNameSet messageDestinationQNameSet;
072 private final QNameSet messageDestinationRefQNameSet;
073
074 private static final QName GER_ADMIN_OBJECT_REF_QNAME = GerResourceEnvRefDocument.type.getDocumentElementName();
075 private static final QNameSet GER_ADMIN_OBJECT_REF_QNAME_SET = QNameSet.singleton(GER_ADMIN_OBJECT_REF_QNAME);
076 private static final QName GER_MESSAGE_DESTINATION_QNAME = GerMessageDestinationDocument.type.getDocumentElementName();
077 private static final QNameSet GER_MESSAGE_DESTINATION_QNAME_SET = QNameSet.singleton(GER_MESSAGE_DESTINATION_QNAME);
078
079 public AdminObjectRefBuilder(Environment defaultEnvironment, String[] eeNamespaces) {
080 super(defaultEnvironment);
081 adminOjbectRefQNameSet = buildQNameSet(eeNamespaces, "resource-env-ref");
082 messageDestinationQNameSet = buildQNameSet(eeNamespaces, "message-destination");
083 messageDestinationRefQNameSet = buildQNameSet(eeNamespaces, "message-destination-ref");
084 }
085
086 protected boolean willMergeEnvironment(XmlObject specDD, XmlObject plan) {
087 return specDD.selectChildren(adminOjbectRefQNameSet).length > 0 || specDD.selectChildren(messageDestinationRefQNameSet).length > 0;
088 }
089
090 public void initContext(XmlObject specDD, XmlObject plan, Module module) throws DeploymentException {
091 List<MessageDestinationType> specDestinations = convert(specDD.selectChildren(messageDestinationQNameSet), JEE_CONVERTER, MessageDestinationType.class, MessageDestinationType.type);
092 XmlObject[] gerDestinations = plan.selectChildren(GER_MESSAGE_DESTINATION_QNAME_SET);
093 Map<String, GerMessageDestinationType> nameMap = new HashMap<String, GerMessageDestinationType>();
094 for (XmlObject gerDestination : gerDestinations) {
095 GerMessageDestinationType destination = (GerMessageDestinationType) gerDestination.copy().changeType(GerMessageDestinationType.type);
096 String name = destination.getMessageDestinationName().trim();
097 nameMap.put(name, destination);
098 boolean found = false;
099 for (MessageDestinationType specDestination : specDestinations) {
100 if (specDestination.getMessageDestinationName().getStringValue().trim().equals(name)) {
101 found = true;
102 break;
103 }
104 }
105 if (!found) {
106 throw new DeploymentException("No spec DD message-destination for " + name);
107 }
108 }
109 module.getRootEarContext().registerMessageDestionations(module.getName(), nameMap);
110 }
111
112
113 public void buildNaming(XmlObject specDD, XmlObject plan, Module module, Map componentContext) throws DeploymentException {
114 XmlObject[] gerResourceEnvRefsUntyped = plan == null ? NO_REFS : plan.selectChildren(GER_ADMIN_OBJECT_REF_QNAME_SET);
115 Map<String, GerResourceEnvRefType> refMap = mapResourceEnvRefs(gerResourceEnvRefsUntyped);
116 Map<String, Map<String, GerMessageDestinationType>> messageDestinations = module.getRootEarContext().getMessageDestinations();
117
118 // Discover and process any @Resource annotations (if !metadata-complete)
119 if (module.getClassFinder() != null) {
120
121 // Process all the annotations for this naming builder type
122 try {
123 ResourceAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder(), new AdminObjectRefProcessor(refMap, messageDestinations, module.getEarContext()));
124 }
125 catch (Exception e) {
126 log.warn("Unable to process @Resource annotations for module" + module.getName(), e);
127 }
128 }
129
130 List<ResourceEnvRefType> resourceEnvRefsUntyped = convert(specDD.selectChildren(adminOjbectRefQNameSet), JEE_CONVERTER, ResourceEnvRefType.class, ResourceEnvRefType.type);
131 ClassLoader cl = module.getEarContext().getClassLoader();
132 for (ResourceEnvRefType resourceEnvRef : resourceEnvRefsUntyped) {
133 String name = resourceEnvRef.getResourceEnvRefName().getStringValue().trim();
134 addInjections(name, resourceEnvRef.getInjectionTargetArray(), componentContext);
135 String type = resourceEnvRef.getResourceEnvRefType().getStringValue().trim();
136 Class iface;
137 try {
138 iface = cl.loadClass(type);
139 } catch (ClassNotFoundException e) {
140 throw new DeploymentException("could not load class " + type, e);
141 }
142 GerResourceEnvRefType gerResourceEnvRef = refMap.get(name);
143 refMap.remove(name);
144 try {
145 String refType = getStringValue(resourceEnvRef.getResourceEnvRefType());
146 if (refType.equals("javax.transaction.UserTransaction")) {
147 Reference ref = new UserTransactionReference();
148 getJndiContextMap(componentContext).put(ENV + name, ref);
149 } else {
150 AbstractNameQuery containerId = getAdminObjectContainerId(name, gerResourceEnvRef);
151 Reference ref = buildAdminObjectReference(module, containerId, iface);
152 getJndiContextMap(componentContext).put(ENV + name, ref);
153 }
154 } catch (UnresolvedReferenceException e) {
155 throw new DeploymentException("Unable to resolve resource env reference '" + name + "' (" + (e.isMultiple() ? "found multiple matching resources" : "no matching resources found") + ")", e);
156 }
157 }
158
159 if (refMap.size() > 0) {
160 log.warn("Failed to build reference to Admin object reference "+refMap.keySet()+" defined in plan file, reason - corresponding entry in deployment descriptor missing.");
161 }
162
163 //message-destination-refs
164 List<MessageDestinationRefType> messageDestinationRefsUntyped = convert(specDD.selectChildren(messageDestinationRefQNameSet), JEE_CONVERTER, MessageDestinationRefType.class, MessageDestinationRefType.type);
165
166 for (MessageDestinationRefType messageDestinationRef : messageDestinationRefsUntyped) {
167 String name = getStringValue(messageDestinationRef.getMessageDestinationRefName());
168 addInjections(name, messageDestinationRef.getInjectionTargetArray(), componentContext);
169 String linkName = getStringValue(messageDestinationRef.getMessageDestinationLink());
170 //TODO figure out something better to do here!
171 if (linkName == null) {
172 linkName = name;
173 }
174 String type = getStringValue(messageDestinationRef.getMessageDestinationType());
175 if (type == null) {
176 //must have an injection target to determine type EE5.8.1.3
177 InjectionTargetType[] targets = messageDestinationRef.getInjectionTargetArray();
178 if (targets.length == 0) {
179 throw new DeploymentException("No type for message-destination-ref can be determined from explicit specification or injection target: " + messageDestinationRef);
180 }
181 type = getStringValue(targets[0].getInjectionTargetClass());
182 if (type == null) {
183 throw new DeploymentException("no type for message destination ref in injection target: " + targets[0]);
184 }
185 }
186 Class iface;
187 try {
188 iface = cl.loadClass(type);
189 } catch (ClassNotFoundException e) {
190 throw new DeploymentException("could not load class " + type, e);
191 }
192 String moduleURI = null;
193 GerMessageDestinationType destination = getMessageDestination(linkName, messageDestinations);
194 if (destination != null) {
195 if (destination.isSetAdminObjectLink()) {
196 if (destination.isSetAdminObjectModule()) {
197 moduleURI = destination.getAdminObjectModule().trim();
198 }
199 linkName = destination.getAdminObjectLink().trim();
200 }
201 } else {
202 //well, we know for sure an admin object is not going to be defined in a modules that can have a message-destination
203 int pos = linkName.indexOf('#');
204 if (pos > -1) {
205 //AMM -- the following line causes blowups; e.g. to look in DayTrader EJB module for a RA -- why is that?!?
206 //moduleURI = linkName.substring(0, pos);
207 linkName = linkName.substring(pos + 1);
208 }
209 }
210
211 //try to resolve ref based only matching resource-ref-name
212 //throws exception if it can't locate ref.
213 AbstractNameQuery containerId = buildAbstractNameQuery(null, moduleURI, linkName, NameFactory.JCA_ADMIN_OBJECT, NameFactory.RESOURCE_ADAPTER_MODULE);
214 Reference ref = buildAdminObjectReference(module, containerId, iface);
215 getJndiContextMap(componentContext).put(ENV + name, ref);
216
217 }
218
219 }
220
221 public static GerMessageDestinationType getMessageDestination(String messageDestinationLink, Map<String, Map<String, GerMessageDestinationType>> messageDestinations) throws DeploymentException {
222 GerMessageDestinationType destination = null;
223 int pos = messageDestinationLink.indexOf('#');
224 if (pos > -1) {
225 String targetModule = messageDestinationLink.substring(0, pos);
226 Map<String, GerMessageDestinationType> destinations = messageDestinations.get(targetModule);
227 // Hmmm...if we don't find the module then something is wrong in the deployment.
228 if (destinations == null) {
229 StringBuffer sb = new StringBuffer();
230 for (Object o : messageDestinations.keySet()) {
231 sb.append(o).append("\n");
232 }
233 throw new DeploymentException("Unknown module " + targetModule + " when processing message destination " + messageDestinationLink +
234 "\nKnown modules in deployable unit are:\n" + sb.toString());
235 }
236 messageDestinationLink = messageDestinationLink.substring(pos + 1);
237 destination = destinations.get(messageDestinationLink);
238 } else {
239 for (Map<String, GerMessageDestinationType> destinations : messageDestinations.values()) {
240 GerMessageDestinationType destinationTest = destinations.get(messageDestinationLink);
241 if (destinationTest != null) {
242 if (destination != null) {
243 throw new DeploymentException("Duplicate message destination " + messageDestinationLink + " accessed from a message-destination-link without a module");
244 }
245 destination = destinationTest;
246 }
247 }
248 }
249 return destination;
250 }
251
252
253 private Reference buildAdminObjectReference(Module module, AbstractNameQuery containerId, Class iface) throws DeploymentException {
254 Configuration localConfiguration = module.getEarContext().getConfiguration();
255 try {
256 localConfiguration.findGBean(containerId);
257 } catch (GBeanNotFoundException e) {
258 throw new DeploymentException("Can not resolve admin object ref " + containerId + " in configuration " + localConfiguration.getId(), e);
259 }
260 return new ResourceReference(module.getConfigId(), containerId, iface);
261 }
262
263 private static AbstractNameQuery getAdminObjectContainerId(String name, GerResourceEnvRefType gerResourceEnvRef) {
264 AbstractNameQuery containerId;
265 if (gerResourceEnvRef == null) {
266 containerId = buildAbstractNameQuery(null, null, name, NameFactory.JCA_ADMIN_OBJECT, NameFactory.RESOURCE_ADAPTER_MODULE);
267 } else if (gerResourceEnvRef.isSetMessageDestinationLink()) {
268 containerId = buildAbstractNameQuery(null, null, gerResourceEnvRef.getMessageDestinationLink().trim(), NameFactory.JCA_ADMIN_OBJECT, NameFactory.RESOURCE_ADAPTER_MODULE);
269 } else if (gerResourceEnvRef.isSetAdminObjectLink()) {
270 String moduleURI = null;
271 if (gerResourceEnvRef.isSetAdminObjectModule()) {
272 moduleURI = gerResourceEnvRef.getAdminObjectModule().trim();
273 }
274 containerId = buildAbstractNameQuery(null, moduleURI, gerResourceEnvRef.getAdminObjectLink().trim(), NameFactory.JCA_ADMIN_OBJECT, NameFactory.RESOURCE_ADAPTER_MODULE);
275 } else {
276 //construct name from components
277 GerPatternType patternType = gerResourceEnvRef.getPattern();
278 containerId = buildAbstractNameQuery(patternType, NameFactory.JCA_ADMIN_OBJECT, NameFactory.RESOURCE_ADAPTER_MODULE, null);
279 }
280 return containerId;
281 }
282
283 private static Map<String, GerResourceEnvRefType> mapResourceEnvRefs(XmlObject[] refs) {
284 Map<String, GerResourceEnvRefType> refMap = new HashMap<String, GerResourceEnvRefType>();
285 if (refs != null) {
286 for (XmlObject ref1 : refs) {
287 GerResourceEnvRefType ref = (GerResourceEnvRefType) ref1.copy().changeType(GerResourceEnvRefType.type);
288 refMap.put(ref.getRefName().trim(), ref);
289 }
290 }
291 return refMap;
292 }
293
294 public QNameSet getSpecQNameSet() {
295 return adminOjbectRefQNameSet;
296 }
297
298 public QNameSet getPlanQNameSet() {
299 return GER_ADMIN_OBJECT_REF_QNAME_SET;
300 }
301
302 public static class AdminObjectRefProcessor extends ResourceAnnotationHelper.ResourceProcessor {
303 private final EARContext earContext;
304 private final Map<String, GerResourceEnvRefType> refMap;
305 private final Map<String, Map<String, GerMessageDestinationType>> messageDestinations;
306
307 public AdminObjectRefProcessor(Map<String, GerResourceEnvRefType> refMap, Map<String, Map<String, GerMessageDestinationType>> messageDestinations, EARContext earContext) {
308 this.refMap = refMap;
309 this.messageDestinations = messageDestinations;
310 this.earContext = earContext;
311 }
312
313 public boolean processResource(AnnotatedApp annotatedApp, Resource annotation, Class cls, Method method, Field field) throws DeploymentException {
314 String resourceName = getResourceName(annotation, method, field);
315 String resourceType = getResourceType(annotation, method, field);
316
317 if (resourceType.equals("javax.ejb.SessionContext")) return true;
318 if (resourceType.equals("javax.ejb.MessageDrivenContext")) return true;
319 if (resourceType.equals("javax.ejb.EntityContext")) return true;
320
321 //If it already exists in xml as a message-destination-ref or resource-env-ref, we are done.
322 MessageDestinationRefType[] messageDestinationRefs = annotatedApp.getMessageDestinationRefArray();
323 for (MessageDestinationRefType messageDestinationRef : messageDestinationRefs) {
324 if (messageDestinationRef.getMessageDestinationRefName().getStringValue().trim().equals(resourceName)) {
325 if (method != null || field != null) {
326 InjectionTargetType[] targets = messageDestinationRef.getInjectionTargetArray();
327 if (!hasTarget(method, field, targets)) {
328 configureInjectionTarget(messageDestinationRef.addNewInjectionTarget(), method, field);
329 }
330 }
331 return true;
332 }
333 }
334 ResourceEnvRefType[] ResourceEnvRefs = annotatedApp.getResourceEnvRefArray();
335 for (ResourceEnvRefType resourceEnvRefType : ResourceEnvRefs) {
336 if (resourceEnvRefType.getResourceEnvRefName().getStringValue().trim().equals(resourceName)) {
337 if (method != null || field != null) {
338 InjectionTargetType[] targets = resourceEnvRefType.getInjectionTargetArray();
339 if (!hasTarget(method, field, targets)) {
340 configureInjectionTarget(resourceEnvRefType.addNewInjectionTarget(), method, field);
341 }
342 }
343 return true;
344 }
345 }
346
347 //if it maps to a message-destination in the geronimo plan, it's a message-destination.
348 GerMessageDestinationType gerMessageDestinationType = getMessageDestination(resourceName, messageDestinations);
349 if (gerMessageDestinationType != null) {
350 addMethodDestinationRef(annotatedApp, resourceName, resourceType, method, field, annotation);
351 return true;
352 } else {
353 //if it maps to a resource-env-ref in the geronimo plan, it's a resource-ref
354 GerResourceEnvRefType resourceEnvRefType = refMap.get(resourceName);
355 if (resourceEnvRefType != null || resourceType.equals("javax.transaction.UserTransaction")) {
356 //mapped resource-env-ref
357 addResourceEnvRef(annotatedApp, resourceName, resourceType, method, field, annotation);
358 return true;
359 } else {
360 //look for an JCAAdminObject gbean with the right name
361 AbstractNameQuery containerId = buildAbstractNameQuery(null, null, resourceName, NameFactory.JCA_ADMIN_OBJECT, NameFactory.RESOURCE_ADAPTER_MODULE);
362 try {
363 earContext.findGBean(containerId);
364 } catch (GBeanNotFoundException e) {
365 //not identifiable as an admin object ref
366 return false;
367 }
368 addResourceEnvRef(annotatedApp, resourceName, resourceType, method, field, annotation);
369 return true;
370 }
371 }
372 }
373
374 private void addResourceEnvRef(AnnotatedApp annotatedApp, String resourceName, String resourceType, Method method, Field field, Resource annotation) {
375 ResourceEnvRefType resourceEnvRef = annotatedApp.addNewResourceEnvRef();
376
377 //------------------------------------------------------------------------------
378 // <resource-env-ref> required elements:
379 //------------------------------------------------------------------------------
380
381 // resource-env-ref-name
382 JndiNameType resourceEnvRefName = resourceEnvRef.addNewResourceEnvRefName();
383 resourceEnvRefName.setStringValue(resourceName);
384 resourceEnvRef.setResourceEnvRefName(resourceEnvRefName);
385
386 if (!resourceType.equals("")) {
387 // resource-env-ref-type
388 FullyQualifiedClassType qualifiedClass = resourceEnvRef.addNewResourceEnvRefType();
389 qualifiedClass.setStringValue(resourceType);
390 resourceEnvRef.setResourceEnvRefType(qualifiedClass);
391 }
392 if (method != null || field != null) {
393 // injectionTarget
394 InjectionTargetType injectionTarget = resourceEnvRef.addNewInjectionTarget();
395 configureInjectionTarget(injectionTarget, method, field);
396 }
397
398 //------------------------------------------------------------------------------
399 // <resource-env-ref> optional elements:
400 //------------------------------------------------------------------------------
401
402 // description
403 String descriptionAnnotation = annotation.description();
404 if (!descriptionAnnotation.equals("")) {
405 DescriptionType description = resourceEnvRef.addNewDescription();
406 description.setStringValue(descriptionAnnotation);
407 }
408
409 // mappedName
410 String mappdedNameAnnotation = annotation.mappedName();
411 if (!mappdedNameAnnotation.equals("")) {
412 XsdStringType mappedName = resourceEnvRef.addNewMappedName();
413 mappedName.setStringValue(mappdedNameAnnotation);
414 resourceEnvRef.setMappedName(mappedName);
415 }
416 }
417
418 private void addMethodDestinationRef(AnnotatedApp annotatedApp, String resourceName, String resourceType, Method method, Field field, Resource annotation) {
419 MessageDestinationRefType messageDestinationRef = annotatedApp.addNewMessageDestinationRef();
420
421 //------------------------------------------------------------------------------
422 // <message-destination-ref> required elements:
423 //------------------------------------------------------------------------------
424
425 // message-destination-ref-name
426 JndiNameType messageDestinationRefName = messageDestinationRef.addNewMessageDestinationRefName();
427 messageDestinationRefName.setStringValue(resourceName);
428 messageDestinationRef.setMessageDestinationRefName(messageDestinationRefName);
429
430 if (!resourceType.equals("")) {
431 // message-destination-ref-type
432 MessageDestinationTypeType msgDestType = messageDestinationRef.addNewMessageDestinationType();
433 msgDestType.setStringValue(resourceType);
434 messageDestinationRef.setMessageDestinationType(msgDestType);
435 }
436 if (method != null || field != null) {
437 // injectionTarget
438 InjectionTargetType injectionTarget = messageDestinationRef.addNewInjectionTarget();
439 configureInjectionTarget(injectionTarget, method, field);
440 }
441
442 //------------------------------------------------------------------------------
443 // <message-destination-ref> optional elements:
444 //------------------------------------------------------------------------------
445
446 // description
447 String descriptionAnnotation = annotation.description();
448 if (!descriptionAnnotation.equals("")) {
449 DescriptionType description = messageDestinationRef.addNewDescription();
450 description.setStringValue(descriptionAnnotation);
451 }
452
453 // mappedName
454 String mappdedNameAnnotation = annotation.mappedName();
455 if (!mappdedNameAnnotation.equals("")) {
456 XsdStringType mappedName = messageDestinationRef.addNewMappedName();
457 mappedName.setStringValue(mappdedNameAnnotation);
458 messageDestinationRef.setMappedName(mappedName);
459 }
460 }
461 }
462
463 public static final GBeanInfo GBEAN_INFO;
464
465 static {
466 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(AdminObjectRefBuilder.class, NameFactory.MODULE_BUILDER);
467 infoBuilder.addAttribute("eeNamespaces", String[].class, true, true);
468 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
469
470 infoBuilder.setConstructor(new String[]{"defaultEnvironment", "eeNamespaces"});
471
472 GBEAN_INFO = infoBuilder.getBeanInfo();
473 }
474
475 public static GBeanInfo getGBeanInfo
476 () {
477 return GBEAN_INFO;
478 }
479
480 }