KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > gbean > runtime > GBeanInstance


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.geronimo.gbean.runtime;
19
20 import java.io.PrintWriter JavaDoc;
21 import java.io.StringWriter JavaDoc;
22 import java.lang.reflect.Constructor JavaDoc;
23 import java.lang.reflect.InvocationTargetException JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.LinkedHashSet JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Set JavaDoc;
33 import java.util.Arrays JavaDoc;
34
35 import javax.management.ObjectName JavaDoc;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.geronimo.gbean.AbstractName;
40 import org.apache.geronimo.gbean.AbstractNameQuery;
41 import org.apache.geronimo.gbean.GAttributeInfo;
42 import org.apache.geronimo.gbean.GBeanData;
43 import org.apache.geronimo.gbean.GBeanInfo;
44 import org.apache.geronimo.gbean.GBeanLifecycle;
45 import org.apache.geronimo.gbean.GConstructorInfo;
46 import org.apache.geronimo.gbean.GOperationInfo;
47 import org.apache.geronimo.gbean.GOperationSignature;
48 import org.apache.geronimo.gbean.GReferenceInfo;
49 import org.apache.geronimo.gbean.InvalidConfigurationException;
50 import org.apache.geronimo.gbean.ReferencePatterns;
51 import org.apache.geronimo.kernel.DependencyManager;
52 import org.apache.geronimo.kernel.GBeanNotFoundException;
53 import org.apache.geronimo.kernel.Kernel;
54 import org.apache.geronimo.kernel.NoSuchAttributeException;
55 import org.apache.geronimo.kernel.NoSuchOperationException;
56 import org.apache.geronimo.kernel.repository.Artifact;
57 import org.apache.geronimo.kernel.config.ManageableAttributeStore;
58 import org.apache.geronimo.kernel.management.State;
59 import org.apache.geronimo.kernel.management.StateManageable;
60
61 /**
62  * A GBeanInstance is a J2EE Management Managed Object, and is standard base for Geronimo services.
63  *
64  * @version $Rev:385718 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
65  */

66 public final class GBeanInstance implements StateManageable {
67     private static final Log log = LogFactory.getLog(GBeanInstance.class);
68
69     private static final int DESTROYED = 0;
70     private static final int CREATING = 1;
71     private static final int RUNNING = 2;
72     private static final int DESTROYING = 3;
73
74     /**
75      * Attribute name used to retrieve the RawInvoker for the GBean
76      */

77     public static final String JavaDoc RAW_INVOKER = "$$RAW_INVOKER$$";
78
79     /**
80      * The kernel in which this server is registered.
81      */

82     private final Kernel kernel;
83
84     /**
85      * The ManageableAttributeStore notified of any changes to manageable
86      * attributes. This is lazy-loaded as manageable attributes are set.
87      */

88     private ManageableAttributeStore manageableStore;
89
90     /**
91      * the abstract name of this service
92      */

93     private final AbstractName abstractName;
94
95     /**
96      * This handles all state transiitions for this instance.
97      */

98     private final GBeanInstanceState gbeanInstanceState;
99
100     /**
101      * The constructor used to create the instance
102      */

103     private final Constructor JavaDoc constructor;
104
105     /**
106      * A fast index based raw invoker for this GBean.
107      */

108     private final RawInvoker rawInvoker;
109
110     /**
111      * The single listener to which we broadcast lifecycle change events.
112      */

113     private final LifecycleBroadcaster lifecycleBroadcaster;
114
115     /**
116      * Interfaces for this GBean
117      */

118     private final String JavaDoc[] interfaces;
119
120     /**
121      * Attributes lookup table
122      */

123     private final GBeanAttribute[] attributes;
124
125     /**
126      * Attributes supported by this GBeanMBean by (String) name.
127      */

128     private final Map JavaDoc attributeIndex = new HashMap JavaDoc();
129
130     /**
131      * References lookup table
132      */

133     private final GBeanReference[] references;
134
135     /**
136      * References supported by this GBeanMBean by (String) name.
137      */

138     private final Map JavaDoc referenceIndex = new HashMap JavaDoc();
139
140     /**
141      * Dependencies supported by this GBean.
142      */

143     private final GBeanDependency[] dependencies;
144
145     /**
146      * Operations lookup table
147      */

148     private final GBeanOperation[] operations;
149
150     /**
151      * Operations supported by this GBeanMBean by (GOperationSignature) name.
152      */

153     private final Map JavaDoc operationIndex = new HashMap JavaDoc();
154
155     /**
156      * The classloader used for all invocations and creating targets.
157      */

158     private final ClassLoader JavaDoc classLoader;
159
160     /**
161      * Metadata describing the attributes, operations and references of this GBean
162      */

163     private final GBeanInfo gbeanInfo;
164
165     /**
166      * Our name
167      */

168     private final String JavaDoc name;
169
170     /**
171      * Java type of the wrapped GBean class
172      */

173     private final Class JavaDoc type;
174
175     /**
176      * Has this instance been destroyed?
177      */

178     private boolean dead = false;
179
180     /**
181      * The state of the internal gbean instance that we are wrapping.
182      */

183     private int instanceState = DESTROYED;
184
185     /**
186      * Target instance of this GBean wrapper
187      */

188     private Object JavaDoc target;
189
190     /**
191      * The time this application started.
192      */

193     private long startTime;
194
195     /**
196      * This is used to signal the creating thread that it should
197      * fail when it returns from usercode. This is set when a
198      * reference has gone offline during construction.
199      */

200     private boolean shouldFail = false;
201
202     /**
203      * Used to track instance
204      */

205     private InstanceRegistry instanceRegistry;
206
207     private String JavaDoc stateReason;
208
209     /**
210      * Construct a GBeanMBean using the supplied GBeanData and class loader
211      *
212      * @param gbeanData the data for the new GBean including GBeanInfo, intial attribute values, and reference patterns
213      * @param classLoader the class loader used to load the gbean instance and attribute/reference types
214      * @throws org.apache.geronimo.gbean.InvalidConfigurationException
215      * if the gbeanInfo is inconsistent with the actual java classes, such as
216      * mismatched attribute types or the intial data cannot be set
217      */

218     public GBeanInstance(GBeanData gbeanData, Kernel kernel, DependencyManager dependencyManager, LifecycleBroadcaster lifecycleBroadcaster, ClassLoader JavaDoc classLoader) throws InvalidConfigurationException {
219         this.abstractName = gbeanData.getAbstractName();
220         this.kernel = kernel;
221         this.lifecycleBroadcaster = lifecycleBroadcaster;
222         this.gbeanInstanceState = new GBeanInstanceState(abstractName, kernel, dependencyManager, this, lifecycleBroadcaster);
223         this.classLoader = classLoader;
224
225         GBeanInfo gbeanInfo = gbeanData.getGBeanInfo();
226         try {
227             type = classLoader.loadClass(gbeanInfo.getClassName());
228         } catch (ClassNotFoundException JavaDoc e) {
229             throw new InvalidConfigurationException("Could not load GBeanInfo class from classloader: " + classLoader +
230                     " className=" + gbeanInfo.getClassName());
231         }
232
233         name = gbeanInfo.getName();
234
235         //
236
Set JavaDoc constructorArgs = new HashSet JavaDoc(gbeanInfo.getConstructor().getAttributeNames());
237
238         // interfaces
239
interfaces = (String JavaDoc[]) gbeanInfo.getInterfaces().toArray(new String JavaDoc[0]);
240
241         // attributes
242
Map JavaDoc attributesMap = new HashMap JavaDoc();
243         for (Iterator JavaDoc iterator = gbeanInfo.getAttributes().iterator(); iterator.hasNext();) {
244             GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
245             attributesMap.put(attributeInfo.getName(), new GBeanAttribute(this, attributeInfo, constructorArgs.contains(attributeInfo.getName())));
246         }
247         addManagedObjectAttributes(attributesMap);
248         attributes = (GBeanAttribute[]) attributesMap.values().toArray(new GBeanAttribute[attributesMap.size()]);
249         for (int i = 0; i < attributes.length; i++) {
250             attributeIndex.put(attributes[i].getName(), new Integer JavaDoc(i));
251         }
252
253         // references
254
Set JavaDoc referencesSet = new HashSet JavaDoc();
255         Set JavaDoc dependencySet = new HashSet JavaDoc();
256         // add the references
257
Map JavaDoc dataReferences = gbeanData.getReferences();
258         for (Iterator JavaDoc iterator = gbeanInfo.getReferences().iterator(); iterator.hasNext();) {
259             GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
260             String JavaDoc referenceName = referenceInfo.getName();
261             ReferencePatterns referencePatterns = (ReferencePatterns) dataReferences.remove(referenceName);
262             if (referenceInfo.getProxyType().equals(Collection JavaDoc.class.getName())) {
263                 referencesSet.add(new GBeanCollectionReference(this, referenceInfo, kernel, referencePatterns));
264
265             } else {
266                 referencesSet.add(new GBeanSingleReference(this, referenceInfo, kernel, referencePatterns));
267                 if (referencePatterns != null) {
268                     dependencySet.add(new GBeanDependency(this, referencePatterns.getAbstractName(), kernel));
269                 }
270             }
271         }
272         if (!dataReferences.isEmpty()) {
273             throw new IllegalStateException JavaDoc("Attempting to set unknown references: " + dataReferences.keySet());
274         }
275
276         references = (GBeanReference[]) referencesSet.toArray(new GBeanReference[referencesSet.size()]);
277         for (int i = 0; i < references.length; i++) {
278             referenceIndex.put(references[i].getName(), new Integer JavaDoc(i));
279         }
280
281         //dependencies
282
for (Iterator JavaDoc iterator = gbeanData.getDependencies().iterator(); iterator.hasNext();) {
283             AbstractName dependencyName = ((ReferencePatterns) iterator.next()).getAbstractName();
284             dependencySet.add(new GBeanDependency(this, dependencyName, kernel));
285         }
286
287         dependencies = (GBeanDependency[]) dependencySet.toArray(new GBeanDependency[dependencySet.size()]);
288
289         // framework operations -- all framework operations have currently been removed
290

291         // operations
292
Map JavaDoc operationsMap = new HashMap JavaDoc();
293         for (Iterator JavaDoc iterator = gbeanInfo.getOperations().iterator(); iterator.hasNext();) {
294             GOperationInfo operationInfo = (GOperationInfo) iterator.next();
295             GOperationSignature signature = new GOperationSignature(operationInfo.getName(), operationInfo.getParameterList());
296             // do not allow overriding of framework operations
297
if (!operationsMap.containsKey(signature)) {
298                 GBeanOperation operation = new GBeanOperation(this, operationInfo);
299                 operationsMap.put(signature, operation);
300             }
301         }
302         operations = new GBeanOperation[operationsMap.size()];
303         int opCounter = 0;
304         for (Iterator JavaDoc iterator = operationsMap.entrySet().iterator(); iterator.hasNext();) {
305             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
306             operations[opCounter] = (GBeanOperation) entry.getValue();
307             operationIndex.put(entry.getKey(), new Integer JavaDoc(opCounter));
308             opCounter++;
309         }
310
311         // get the constructor
312
List JavaDoc arguments = gbeanInfo.getConstructor().getAttributeNames();
313         Class JavaDoc[] parameterTypes = new Class JavaDoc[arguments.size()];
314         for (int i = 0; i < parameterTypes.length; i++) {
315             String JavaDoc argumentName = (String JavaDoc) arguments.get(i);
316             if (referenceIndex.containsKey(argumentName)) {
317                 Integer JavaDoc index = (Integer JavaDoc) referenceIndex.get(argumentName);
318                 GBeanReference reference = references[index.intValue()];
319                 parameterTypes[i] = reference.getProxyType();
320             } else if (attributeIndex.containsKey(argumentName)) {
321                 Integer JavaDoc index = (Integer JavaDoc) attributeIndex.get(argumentName);
322                 GBeanAttribute attribute = attributes[index.intValue()];
323                 parameterTypes[i] = attribute.getType();
324             }
325         }
326         try {
327             constructor = type.getConstructor(parameterTypes);
328         } catch (NoSuchMethodException JavaDoc e) {
329             StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Could not find a valid constructor for GBean: ").append(gbeanInfo.getName()).append("\n");
330             buf.append("ParameterTypes: ").append(Arrays.asList(parameterTypes)).append("\n");
331             Constructor JavaDoc[] constructors = type.getConstructors();
332             for (int i = 0; i < constructors.length; i++) {
333                 Constructor JavaDoc testConstructor = constructors[i];
334                 buf.append("constructor types: ").append(Arrays.asList(testConstructor.getParameterTypes())).append("\n");
335                 if (testConstructor.getParameterTypes().length == parameterTypes.length) {
336                     Class JavaDoc[] testParameterTypes = testConstructor.getParameterTypes();
337                     for (int k = 0; k < testParameterTypes.length; k++) {
338                         Class JavaDoc testParameterType = testParameterTypes[k];
339                         if (parameterTypes[k].getName().equals(testParameterType.getName())) {
340                             if (parameterTypes[k].getClassLoader() != testParameterType.getClassLoader()) {
341                                 buf.append("different classloaders in position: ").append(k).append(" class name: ").append(testParameterType.getName()).append("\n");
342                                 buf.append("parameter type classloader: ").append(parameterTypes[k].getClassLoader()).append("\n");
343                                 buf.append("constructor type classloader: ").append(testParameterType.getClassLoader()).append("\n");
344                             }
345                         } else {
346                             buf.append("different type in position: ").append(k).append("\n");
347                         }
348                     }
349                 }
350             }
351             throw new InvalidConfigurationException(buf.toString());
352         }
353
354         // rebuild the gbean info based on the current attributes, operations, and references because
355
// the above code add new attributes and operations
356
this.gbeanInfo = rebuildGBeanInfo(gbeanInfo.getConstructor(), gbeanInfo.getJ2eeType());
357
358         // create the raw invokers
359
rawInvoker = new RawInvoker(this);
360
361         // set the initial attribute values
362
try {
363             // set the attributes
364
Map JavaDoc dataAttributes = gbeanData.getAttributes();
365             for (Iterator JavaDoc iterator = dataAttributes.entrySet().iterator(); iterator.hasNext();) {
366                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
367                 String JavaDoc attributeName = (String JavaDoc) entry.getKey();
368                 Object JavaDoc attributeValue = entry.getValue();
369                     if (entry.getValue() != null) {
370                         setAttribute(attributeName, attributeValue, false);
371                     }
372             }
373
374         } catch (Exception JavaDoc e) {
375             throw new InvalidConfigurationException("Could not inject configuration data into the GBean " + abstractName, e);
376         }
377
378         for (int i = 0; i < dependencies.length; i++) {
379             dependencies[i].online();
380         }
381         for (int i = 0; i < references.length; i++) {
382             references[i].online();
383         }
384     }
385
386     public void die() throws GBeanNotFoundException {
387         synchronized (this) {
388             if (dead) {
389                 // someone beat us to the punch... this instance should have never been found in the first place
390
throw new GBeanNotFoundException(abstractName);
391             }
392             dead = true;
393         }
394
395         // if the bean is already stopped or failed, this will do nothing; otherwise it will shutdown the bean
396
gbeanInstanceState.fail();
397
398         for (int i = 0; i < references.length; i++) {
399             references[i].offline();
400         }
401         for (int i = 0; i < dependencies.length; i++) {
402             dependencies[i].offline();
403         }
404
405         // tell everyone we are done
406
lifecycleBroadcaster.fireUnloadedEvent();
407
408         manageableStore = null;
409     }
410
411     public synchronized void setInstanceRegistry(InstanceRegistry instanceRegistry) {
412         this.instanceRegistry = instanceRegistry;
413     }
414
415     /**
416      * Gets the name of the GBean as defined in the gbean info.
417      *
418      * @return the gbean name
419      */

420     public String JavaDoc getName() {
421         return name;
422     }
423
424     /**
425      * The class loader used to build this gbean. This class loader is set into the thread context
426      * class loader before callint the target instace.
427      *
428      * @return the class loader used to build this gbean
429      */

430     public ClassLoader JavaDoc getClassLoader() {
431         return classLoader;
432     }
433
434     /**
435      * Has this gbean instance been destroyed. An destroyed gbean can no longer be used.
436      *
437      * @return true if the gbean has been destroyed
438      */

439     public synchronized boolean isDead() {
440         return dead;
441     }
442
443     /**
444      * Gets the reason we are in the current state.
445      * @return the reason we are in the current state
446      */

447     public String JavaDoc getStateReason() {
448         return stateReason;
449     }
450
451     /**
452      * The java type of the wrapped gbean instance
453      *
454      * @return the java type of the gbean
455      */

456     public Class JavaDoc getType() {
457         return type;
458     }
459
460     public synchronized Object JavaDoc getTarget() {
461         return target;
462     }
463
464     public final String JavaDoc getObjectName() {
465         return abstractName.getObjectName().getCanonicalName();
466     }
467
468     public final ObjectName JavaDoc getObjectNameObject() {
469         return abstractName.getObjectName();
470     }
471
472     public final AbstractName getAbstractName() {
473         return abstractName;
474     }
475
476     public synchronized final long getStartTime() {
477         return startTime;
478     }
479
480     public int getState() {
481         return gbeanInstanceState.getState();
482     }
483
484     public final State getStateInstance() {
485         return gbeanInstanceState.getStateInstance();
486     }
487
488     /**
489      * Gets an unmodifiable map from attribute names to index number (Integer). This index number
490      * can be used to efficiently set or retrieve an attribute value.
491      *
492      * @return an unmodifiable map of attribute indexes by name
493      */

494     public Map JavaDoc getAttributeIndex() {
495         return Collections.unmodifiableMap(new HashMap JavaDoc(attributeIndex));
496     }
497
498     /**
499      * Gets an unmodifiable map from operation signature (GOperationSignature) to index number (Integer).
500      * This index number can be used to efficciently invoke the operation.
501      *
502      * @return an unmodifiable map of operation indexec by signature
503      */

504     public Map JavaDoc getOperationIndex() {
505         return Collections.unmodifiableMap(new HashMap JavaDoc(operationIndex));
506     }
507
508     /**
509      * Gets the GBeanInfo used to build this gbean.
510      *
511      * @return the GBeanInfo used to build this gbean
512      */

513     public GBeanInfo getGBeanInfo() {
514         return gbeanInfo;
515     }
516
517     /**
518      * Moves this GBeanInstance to the starting state and then attempts to move this MBean immediately
519      * to the running state.
520      *
521      * @throws IllegalStateException If the gbean is disabled
522      */

523     public final void start() {
524         synchronized (this) {
525             if (dead) {
526                 throw new IllegalStateException JavaDoc("A dead GBean can not be started: abstractName=" + abstractName);
527             }
528         }
529         gbeanInstanceState.start();
530     }
531
532     /**
533      * Starts this GBeanInstance and then attempts to start all of its start dependent children.
534      *
535      * @throws IllegalStateException If the gbean is disabled
536      */

537     public final void startRecursive() {
538         synchronized (this) {
539             if (dead) {
540                 throw new IllegalStateException JavaDoc("A dead GBean can not be started: abstractName=" + abstractName);
541             }
542         }
543         gbeanInstanceState.startRecursive();
544     }
545
546     /**
547      * Moves this GBeanInstance to the STOPPING state, calls stop on all start dependent children, and then attempt
548      * to move this MBean to the STOPPED state.
549      */

550     public final void stop() {
551         gbeanInstanceState.stop();
552     }
553
554     /**
555      * Moves this GBeanInstance to the FAILED state. There are no calls to dependent children, but they will be
556      * notified using standard J2EE management notification.
557      */

558     final void referenceFailed() {
559         gbeanInstanceState.fail();
560     }
561
562     /**
563      * Gets the gbean data for the gbean held by this gbean mbean.
564      *
565      * @return the gbean data
566      */

567     public GBeanData getGBeanData() {
568         GBeanData gbeanData = new GBeanData(abstractName, gbeanInfo);
569
570         // copy target into local variables from within a synchronized block to gaurentee a consistent read
571
int state;
572         Object JavaDoc instance;
573         synchronized (this) {
574             state = instanceState;
575             instance = target;
576         }
577
578         // add the attributes
579
for (int i = 0; i < attributes.length; i++) {
580             GBeanAttribute attribute = attributes[i];
581             if (attribute.isPersistent()) {
582                 String JavaDoc name = attribute.getName();
583                 Object JavaDoc value;
584                 if ((state != DESTROYED || attribute.isFramework()) && attribute.isReadable()) {
585                     try {
586                         value = attribute.getValue(instance);
587                     } catch (Throwable JavaDoc throwable) {
588                         value = attribute.getPersistentValue();
589                         log.debug("Could not get the current value of persistent attribute. The persistent " +
590                                 "attribute will not reflect the current state attribute. " + attribute.getDescription(), throwable);
591                     }
592                 } else {
593                     value = attribute.getPersistentValue();
594                 }
595                 gbeanData.setAttribute(name, value);
596             }
597         }
598
599         // add the references
600
for (int i = 0; i < references.length; i++) {
601             GBeanReference reference = references[i];
602             String JavaDoc name = reference.getName();
603             if(reference instanceof GBeanSingleReference) {
604                 AbstractName abstractName = ((GBeanSingleReference) reference).getTargetName();
605                 if(abstractName != null) {
606                     gbeanData.setReferencePattern(name, abstractName);
607                 }
608             } else if(reference instanceof GBeanCollectionReference) {
609                 Set JavaDoc patterns = ((GBeanCollectionReference) reference).getPatterns();
610                 if(patterns != null) {
611                     gbeanData.setReferencePatterns(name, patterns);
612                 }
613             } else {
614                 throw new IllegalStateException JavaDoc("Unrecognized GBeanReference '"+reference.getClass().getName()+"'");
615             }
616         }
617         //TODO copy the dependencies??
618
return gbeanData;
619     }
620
621     /**
622      * Gets the attribute value using the attribute index. This is the most efficient way to get
623      * an attribute as it avoids a HashMap lookup.
624      *
625      * @param index the index of the attribute
626      * @return the attribute value
627      * @throws Exception if a target instance throws and exception
628      * @throws IndexOutOfBoundsException if the index is invalid
629      */

630     public Object JavaDoc getAttribute(int index) throws Exception JavaDoc {
631         GBeanAttribute attribute = attributes[index];
632
633         // copy target into local variables from within a synchronized block to gaurentee a consistent read
634
int state;
635         Object JavaDoc instance;
636         synchronized (this) {
637             state = instanceState;
638             instance = target;
639         }
640
641         if (state != DESTROYED || attribute.isFramework()) {
642             return attribute.getValue(instance);
643         } else {
644             if (attribute.isPersistent()) {
645                 return attribute.getPersistentValue();
646             } else {
647                 throw new IllegalStateException JavaDoc("Cannot retrieve the value for non-persistent attribute \"" + attribute.getName() + "\" when GBeanInstance is DESTROYED");
648             }
649         }
650     }
651
652     /**
653      * Gets an attribute's value by name. This get style is less efficient becuse the attribute must
654      * first be looked up in a HashMap.
655      *
656      * @param attributeName the name of the attribute to retrieve
657      * @return the attribute value
658      * @throws Exception if a problem occurs while getting the value
659      * @throws NoSuchAttributeException if the attribute name is not found in the map
660      */

661     public Object JavaDoc getAttribute(String JavaDoc attributeName) throws NoSuchAttributeException, Exception JavaDoc {
662         GBeanAttribute attribute;
663         try {
664             attribute = getAttributeByName(attributeName);
665         } catch (NoSuchAttributeException e) {
666             if (attributeName.equals(RAW_INVOKER)) {
667                 return rawInvoker;
668             }
669             throw e;
670         }
671
672         // copy target into local variables from within a synchronized block to gaurentee a consistent read
673
int state;
674         Object JavaDoc instance;
675         synchronized (this) {
676             state = instanceState;
677             instance = target;
678         }
679
680         if (state != DESTROYED || attribute.isFramework()) {
681             return attribute.getValue(instance);
682         } else {
683             if (attribute.isPersistent()) {
684                 return attribute.getPersistentValue();
685             } else {
686                 throw new IllegalStateException JavaDoc("Cannot retrieve the value for non-persistent attribute " + attributeName + " when gbean has been destroyed: " + abstractName);
687             }
688         }
689     }
690
691     /**
692      * Sets the attribute value using the attribute index. This is the most efficient way to set
693      * an attribute as it avoids a HashMap lookup.
694      *
695      * @param index the index of the attribute
696      * @param value the new value of attribute value
697      * @throws Exception if a target instance throws and exception
698      * @throws IndexOutOfBoundsException if the index is invalid
699      */

700     public void setAttribute(int index, Object JavaDoc value) throws Exception JavaDoc, IndexOutOfBoundsException JavaDoc {
701         setAttribute(index, value, true);
702     }
703
704     private void setAttribute(int index, Object JavaDoc value, boolean manage) throws Exception JavaDoc, IndexOutOfBoundsException JavaDoc {
705         GBeanAttribute attribute = attributes[index];
706
707         // copy target into local variables from within a synchronized block to gaurentee a consistent read
708
int state;
709         Object JavaDoc instance;
710         synchronized (this) {
711             state = instanceState;
712             instance = target;
713         }
714
715         if (state != DESTROYED || attribute.isFramework()) {
716             attribute.setValue(instance, value);
717         } else {
718             attribute.setPersistentValue(value);
719         }
720         if (manage && attribute.isManageable()) {
721             updateManageableAttribute(attribute, value);
722         }
723     }
724
725     /**
726      * Sets an attribute's value by name. This set style is less efficient becuse the attribute must
727      * first be looked up in a HashMap.
728      *
729      * @param attributeName the name of the attribute to retrieve
730      * @param value the new attribute value
731      * @throws Exception if a target instance throws and exception
732      * @throws NoSuchAttributeException if the attribute name is not found in the map
733      */

734     public void setAttribute(String JavaDoc attributeName, Object JavaDoc value) throws Exception JavaDoc, NoSuchAttributeException {
735         setAttribute(attributeName, value, true);
736     }
737
738     public void setAttribute(String JavaDoc attributeName, Object JavaDoc value, boolean manage) throws Exception JavaDoc, NoSuchAttributeException {
739         GBeanAttribute attribute = getAttributeByName(attributeName);
740
741         // copy target into local variables from within a synchronized block to gaurentee a consistent read
742
int state;
743         Object JavaDoc instance;
744         synchronized (this) {
745             state = instanceState;
746             instance = target;
747         }
748
749         if (state != DESTROYED || attribute.isFramework()) {
750             attribute.setValue(instance, value);
751         } else {
752             attribute.setPersistentValue(value);
753         }
754         if (manage && attribute.isManageable()) {
755             updateManageableAttribute(attribute, value);
756         }
757     }
758
759     private void updateManageableAttribute(GBeanAttribute attribute, Object JavaDoc value) {
760         if (manageableStore == null) {
761             manageableStore = getManageableAttributeStore();
762             if (manageableStore == null) {
763                 return;
764             }
765         }
766         Artifact configName = abstractName.getArtifact();
767         if (configName != null) {
768             manageableStore.setValue(configName, abstractName, attribute.getAttributeInfo(), value);
769         } else {
770             log.error("Unable to identify Configuration for GBean " + abstractName + ". Manageable attribute " + attribute.getName() + " was not updated in persistent store.");
771         }
772     }
773
774     private ManageableAttributeStore getManageableAttributeStore() {
775         Set JavaDoc set = kernel.listGBeans(new AbstractNameQuery(ManageableAttributeStore.class.getName()));
776         for (Iterator JavaDoc iterator = set.iterator(); iterator.hasNext();) {
777             AbstractName abstractName1 = (AbstractName) iterator.next();
778             try {
779                 return (ManageableAttributeStore) kernel.getGBean(abstractName1);
780             } catch (GBeanNotFoundException e) {
781                 // ignored... gbean was unregistered
782
}
783         }
784         return null;
785     }
786
787     private GBeanAttribute getAttributeByName(String JavaDoc name) throws NoSuchAttributeException {
788         Integer JavaDoc index = (Integer JavaDoc) attributeIndex.get(name);
789         if (index == null) {
790             throw new NoSuchAttributeException("Unknown attribute \"" + name + "\" in gbean " + abstractName);
791         }
792         return attributes[index.intValue()];
793     }
794
795     /**
796      * Invokes an opreation using the operation index. This is the most efficient way to invoke
797      * an operation as it avoids a HashMap lookup.
798      *
799      * @param index the index of the attribute
800      * @param arguments the arguments to the operation
801      * @return the result of the operation
802      * @throws Exception if a target instance throws and exception
803      * @throws IndexOutOfBoundsException if the index is invalid
804      * @throws IllegalStateException if the gbean instance has been destroyed
805      */

806     public Object JavaDoc invoke(int index, Object JavaDoc[] arguments) throws Exception JavaDoc {
807         GBeanOperation operation = operations[index];
808
809         // copy target into local variables from within a synchronized block to gaurentee a consistent read
810
int state;
811         Object JavaDoc instance;
812         synchronized (this) {
813             state = instanceState;
814             instance = target;
815         }
816
817         if (state == DESTROYED && !operation.isFramework()) {
818             throw new IllegalStateException JavaDoc("Operations can only be invoke while the GBean instance is running: " + abstractName);
819         }
820         return operation.invoke(instance, arguments);
821     }
822
823     /**
824      * Invokes an operation on the target gbean by method signature. This style if invocation is
825      * inefficient, because the target method must be looked up in a hashmap using a freshly constructed
826      * GOperationSignature object.
827      *
828      * @param operationName the name of the operation to invoke
829      * @param arguments arguments to the operation
830      * @param types types of the operation arguemtns
831      * @return the result of the operation
832      * @throws Exception if a target instance throws and exception
833      * @throws NoSuchOperationException if the operation signature is not found in the map
834      * @throws IllegalStateException if the gbean instance has been destroyed
835      */

836     public Object JavaDoc invoke(String JavaDoc operationName, Object JavaDoc[] arguments, String JavaDoc[] types) throws Exception JavaDoc, NoSuchOperationException {
837         GOperationSignature signature = new GOperationSignature(operationName, types);
838         Integer JavaDoc index = (Integer JavaDoc) operationIndex.get(signature);
839         if (index == null) {
840             throw new NoSuchOperationException("Unknown operation " + signature);
841         }
842         GBeanOperation operation = operations[index.intValue()];
843
844         // copy target into local variables from within a synchronized block to gaurentee a consistent read
845
int state;
846         Object JavaDoc instance;
847         synchronized (this) {
848             state = instanceState;
849             instance = target;
850         }
851
852         if (state == DESTROYED && !operation.isFramework()) {
853             throw new IllegalStateException JavaDoc("Operations can only be invoke while the GBean is running: " + abstractName);
854         }
855         return operation.invoke(instance, arguments);
856     }
857
858     private GBeanReference getReferenceByName(String JavaDoc name) {
859         Integer JavaDoc index = (Integer JavaDoc) referenceIndex.get(name);
860         if (index == null) {
861             throw new IllegalArgumentException JavaDoc("Unknown reference " + name);
862         }
863         return references[index.intValue()];
864     }
865
866     boolean createInstance() throws Exception JavaDoc {
867         synchronized (this) {
868             // first check we are still in the correct state to start
869
if (instanceState == CREATING || instanceState == RUNNING) {
870                 // another thread already completed starting
871
return false;
872             } else if (instanceState == DESTROYING) {
873                 // this should never ever happen... this method is protected by the GBeanState class which should
874
// prevent stuff like this happening, but check anyway
875
stateReason = "an internal error has occurred. An was made to start an instance that was still stopping which is an illegal state transition.";
876                 throw new IllegalStateException JavaDoc("A stopping instance can not be started until fully stopped");
877             }
878             assert instanceState == DESTROYED;
879
880             stateReason = null;
881
882             // Call all start on every reference. This way the dependecies are held until we can start
883
LinkedHashSet JavaDoc unstarted = new LinkedHashSet JavaDoc();
884             for (int i = 0; i < dependencies.length; i++) {
885                 if (!dependencies[i].start()) {
886                     unstarted.add(dependencies[i].getTargetName());
887                 }
888             }
889             for (int i = 0; i < references.length; i++) {
890                 if (!references[i].start()) {
891                     if (references[i] instanceof GBeanSingleReference) {
892                         GBeanSingleReference reference = (GBeanSingleReference) references[i];
893                         unstarted.add(reference.getTargetName());
894                     }
895                 }
896             }
897             if (!unstarted.isEmpty()) {
898                 if (unstarted.size() == 1) {
899                     stateReason = unstarted.iterator().next() + " did not start.";
900                 } else {
901                     stateReason = "the following dependent services did not start: " + unstarted;
902                 }
903                 return false;
904             }
905
906             // we are definately going to (try to) start... if this fails the must clean up these variables
907
instanceState = CREATING;
908             startTime = System.currentTimeMillis();
909         }
910
911         ClassLoader JavaDoc oldCL = Thread.currentThread().getContextClassLoader();
912         Thread.currentThread().setContextClassLoader(classLoader);
913         Object JavaDoc instance = null;
914         try {
915             GConstructorInfo constructorInfo = gbeanInfo.getConstructor();
916             Class JavaDoc[] parameterTypes = constructor.getParameterTypes();
917
918             // create constructor parameter array
919
Object JavaDoc[] parameters = new Object JavaDoc[parameterTypes.length];
920             Iterator JavaDoc names = constructorInfo.getAttributeNames().iterator();
921             for (int i = 0; i < parameters.length; i++) {
922                 String JavaDoc name = (String JavaDoc) names.next();
923                 if (referenceIndex.containsKey(name)) {
924                     parameters[i] = getReferenceByName(name).getProxy();
925                 } else if (attributeIndex.containsKey(name)) {
926                     GBeanAttribute attribute = getAttributeByName(name);
927                     parameters[i] = attribute.getPersistentValue();
928                 } else {
929                     stateReason = "the service constructor definition contained the name '" + name + "' which is not a known attribute or reference of the service.";
930                     throw new InvalidConfigurationException("Unknown attribute or reference name in constructor: referenceName=" + name + ", gbean=" + abstractName);
931                 }
932             }
933
934             // create instance
935
try {
936                 instance = constructor.newInstance(parameters);
937             } catch (InvocationTargetException JavaDoc e) {
938                 Throwable JavaDoc targetException = e.getTargetException();
939                 if (targetException instanceof Exception JavaDoc) {
940                     throw (Exception JavaDoc) targetException;
941                 } else if (targetException instanceof Error JavaDoc) {
942                     throw (Error JavaDoc) targetException;
943                 }
944                 stateReason = "the service constructor threw an exception. \n" + printException(e);
945                 throw e;
946             } catch (IllegalArgumentException JavaDoc e) {
947                 stateReason = "the service constructor threw an exception due to a parameter type mismatch. \n" + printException(e);
948                 log.warn("Constructor mismatch for " + abstractName, e);
949                 throw e;
950             }
951
952             // write the target variable in a synchronized block so it is available to all threads
953
// we do this before calling the setters or start method so the bean can be called back
954
// from a setter start method
955
synchronized (this) {
956                 target = instance;
957             }
958
959             // inject the persistent attribute value into the new instance
960
for (int i = 0; i < attributes.length; i++) {
961                 checkIfShouldFail();
962                 try {
963                     attributes[i].inject(instance);
964                 } catch (Exception JavaDoc e) {
965                     stateReason = "the setter for attribute '" + attributes[i].getName() + "' threw an exception. \n" + printException(e);
966                     throw e;
967                 }
968             }
969
970             // inject the proxies into the new instance
971
for (int i = 0; i < references.length; i++) {
972                 checkIfShouldFail();
973                 try {
974                     references[i].inject(instance);
975                 } catch (Exception JavaDoc e) {
976                     stateReason = "the setter for reference '" + references[i].getName() + "' threw an exception. \n" + printException(e);
977                     throw e;
978                 }
979             }
980
981             if (instance instanceof GBeanLifecycle) {
982                 checkIfShouldFail();
983                 try {
984                     ((GBeanLifecycle) instance).doStart();
985                 } catch (Exception JavaDoc e) {
986                     stateReason = "the doStart method threw an exception. \n" + printException(e);
987                     throw e;
988                 }
989             }
990
991
992             // all done... we are now fully running
993
synchronized (this) {
994                 checkIfShouldFail();
995                 if (instanceRegistry != null) {
996                     instanceRegistry.instanceCreated(instance, this);
997                 }
998                 instanceState = RUNNING;
999                 this.notifyAll();
1000            }
1001
1002
1003            stateReason = null;
1004            return true;
1005        } catch (Throwable JavaDoc t) {
1006            // something went wrong... we need to destroy this instance
1007
synchronized (this) {
1008                instanceState = DESTROYING;
1009            }
1010
1011            if (instance instanceof GBeanLifecycle) {
1012                try {
1013                    ((GBeanLifecycle) instance).doFail();
1014                } catch (Throwable JavaDoc ignored) {
1015                    log.error("Problem in doFail of " + abstractName, ignored);
1016                }
1017            }
1018
1019            // bean has been notified... drop our reference
1020
synchronized (this) {
1021                // stop all of the references
1022
for (int i = 0; i < references.length; i++) {
1023                    references[i].stop();
1024                }
1025                for (int i = 0; i < dependencies.length; i++) {
1026                    dependencies[i].stop();
1027                }
1028
1029                target = null;
1030                instanceState = DESTROYED;
1031                startTime = 0;
1032                this.notifyAll();
1033            }
1034
1035            if (t instanceof Exception JavaDoc) {
1036                throw (Exception JavaDoc) t;
1037            } else if (t instanceof Error JavaDoc) {
1038                throw (Error JavaDoc) t;
1039            } else {
1040                throw new Error JavaDoc(t);
1041            }
1042        } finally {
1043            Thread.currentThread().setContextClassLoader(oldCL);
1044        }
1045    }
1046
1047    private String JavaDoc printException(Throwable JavaDoc t) {
1048        StringWriter JavaDoc stringWriter = new StringWriter JavaDoc();
1049        PrintWriter JavaDoc printWriter = new PrintWriter JavaDoc(stringWriter);
1050        t.printStackTrace(printWriter);
1051        printWriter.flush();
1052        return stringWriter.toString();
1053    }
1054
1055    private synchronized void checkIfShouldFail() throws Exception JavaDoc {
1056        if (shouldFail) {
1057            shouldFail = false;
1058            throw new Exception JavaDoc("A reference has failed so construction can not complete");
1059        }
1060    }
1061
1062    boolean destroyInstance(boolean stop) throws Exception JavaDoc {
1063        Object JavaDoc instance;
1064        synchronized (this) {
1065            if (!stop && instanceState == CREATING) {
1066                // signal to the creating thead that it should fail
1067
shouldFail = true;
1068                return false;
1069            }
1070
1071            // if the instance is being created we need to wait
1072
// for it to finish before we can try to stop it
1073
while (instanceState == CREATING) {
1074                // todo should we limit this wait? If so, how do we configure the wait time?
1075
try {
1076                    this.wait();
1077                } catch (InterruptedException JavaDoc e) {
1078                    // clear the interrupted flag
1079
Thread.interrupted();
1080                    // rethrow the interrupted exception.... someone was sick of us waiting
1081
throw e;
1082                }
1083            }
1084
1085            if (instanceState == DESTROYING || instanceState == DESTROYED) {
1086                // another thread is already stopping or has already stopped
1087
return false;
1088            }
1089            assert instanceState == RUNNING;
1090            stateReason = null;
1091            
1092            // we are definately going to stop... if this fails the must clean up these variables
1093
instanceState = DESTROYING;
1094            instance = target;
1095        }
1096
1097        // update the persistent attributes
1098
// do not update the persistent attibute values in the case of a failure
1099
// failed gbeans may have corrupted attributes that would be persisted
1100
Exception JavaDoc problem = null;
1101        if (stop && instance != null) {
1102            try {
1103                // get all the data but don't update in case there is an exception
1104
Map JavaDoc data = new HashMap JavaDoc();
1105                for (int i = 0; i < attributes.length; i++) {
1106                    GBeanAttribute attribute = attributes[i];
1107                    if (attribute.isPersistent() && attribute.isReadable()) {
1108                        // copy the current attribute value to the persistent value
1109
Object JavaDoc value;
1110                        try {
1111                            value = attribute.getValue(instance);
1112                        } catch (Throwable JavaDoc e) {
1113                            // There is no reason to create a new Exception sub class as this exception will
1114
// simply be caught and logged on GBeanInstanceState
1115
throw new Exception JavaDoc("Problem while updaing the persistent value of attibute: " +
1116                                    "Attribute Name: " + attribute.getName() + ", " +
1117                                    "Type: " + attribute.getType() + ", " +
1118                                    "GBeanInstance: " + getName(), e);
1119                        }
1120                        data.put(attribute, value);
1121                    }
1122                }
1123                // now we have all the data we can update the persistent values
1124
for (int i = 0; i < attributes.length; i++) {
1125                    GBeanAttribute attribute = attributes[i];
1126                    if (attribute.isPersistent() && attribute.isReadable()) {
1127                        // copy the current attribute value to the persistent value
1128
Object JavaDoc value = data.get(attribute);
1129                        attribute.setPersistentValue(value);
1130                    }
1131                }
1132            } catch (Exception JavaDoc e) {
1133                // the getter threw an exception; now we must to fail
1134
stop = false;
1135                problem = e;
1136            }
1137        }
1138
1139        // we notify the bean before removing our reference so the bean can be called back while stopping
1140
ClassLoader JavaDoc oldCL = Thread.currentThread().getContextClassLoader();
1141        Thread.currentThread().setContextClassLoader(classLoader);
1142        try {
1143            if (instance instanceof GBeanLifecycle) {
1144                if (stop) {
1145                    try {
1146                        ((GBeanLifecycle) instance).doStop();
1147                    } catch (Throwable JavaDoc ignored) {
1148                        log.error("Problem in doStop of " + abstractName, ignored);
1149                    }
1150                } else {
1151                    try {
1152                        ((GBeanLifecycle) instance).doFail();
1153                    } catch (Throwable JavaDoc ignored) {
1154                        log.error("Problem in doFail of " + abstractName, ignored);
1155                    }
1156                }
1157            }
1158        } finally {
1159            Thread.currentThread().setContextClassLoader(oldCL);
1160        }
1161
1162        // bean has been notified... drop our reference
1163
synchronized (this) {
1164            // stop all of the references
1165
for (int i = 0; i < references.length; i++) {
1166                references[i].stop();
1167            }
1168            for (int i = 0; i < dependencies.length; i++) {
1169                dependencies[i].stop();
1170            }
1171
1172            target = null;
1173            instanceState = DESTROYED;
1174            if (instanceRegistry != null) {
1175                instanceRegistry.instanceDestroyed(instance);
1176            }
1177            startTime = 0;
1178        }
1179
1180        if (problem != null) {
1181            throw problem;
1182        }
1183        return true;
1184    }
1185
1186    private void addManagedObjectAttributes(Map JavaDoc attributesMap) {
1187        //
1188
// Special attributes
1189
//
1190
attributesMap.put("abstractName",
1191                GBeanAttribute.createSpecialAttribute((GBeanAttribute) attributesMap.get("abstractName"),
1192                        this,
1193                        "abstractName",
1194                        AbstractName.class,
1195                        getAbstractName()));
1196
1197        attributesMap.put("objectName",
1198                GBeanAttribute.createSpecialAttribute((GBeanAttribute) attributesMap.get("objectName"),
1199                        this,
1200                        "objectName",
1201                        String JavaDoc.class,
1202                        getObjectName()));
1203
1204        attributesMap.put("classLoader",
1205                GBeanAttribute.createSpecialAttribute((GBeanAttribute) attributesMap.get("classLoader"),
1206                        this,
1207                        "classLoader",
1208                        ClassLoader JavaDoc.class,
1209                        classLoader));
1210
1211        attributesMap.put("kernel",
1212                GBeanAttribute.createSpecialAttribute((GBeanAttribute) attributesMap.get("kernel"),
1213                        this,
1214                        "kernel",
1215                        Kernel.class,
1216                        kernel));
1217
1218    }
1219
1220    private GBeanInfo rebuildGBeanInfo(GConstructorInfo constructor, String JavaDoc j2eeType) {
1221        Set JavaDoc attributeInfos = new HashSet JavaDoc();
1222        for (int i = 0; i < attributes.length; i++) {
1223            GBeanAttribute attribute = attributes[i];
1224            attributeInfos.add(attribute.getAttributeInfo());
1225        }
1226        Set JavaDoc operationInfos = new HashSet JavaDoc();
1227        for (int i = 0; i < operations.length; i++) {
1228            operationInfos.add(operations[i].getOperationInfo());
1229        }
1230
1231        Set JavaDoc referenceInfos = new HashSet JavaDoc();
1232        for (int i = 0; i < references.length; i++) {
1233            referenceInfos.add(references[i].getReferenceInfo());
1234        }
1235
1236        Set JavaDoc interfaceInfos = new HashSet JavaDoc();
1237        for (int i = 0; i < interfaces.length; i++) {
1238            interfaceInfos.add(interfaces[i]);
1239        }
1240
1241        return new GBeanInfo(name,
1242                type.getName(),
1243                j2eeType,
1244                attributeInfos,
1245                constructor,
1246                operationInfos,
1247                referenceInfos,
1248                interfaceInfos);
1249    }
1250
1251    public boolean equals(Object JavaDoc obj) {
1252        if (obj == this) return true;
1253        if (!(obj instanceof GBeanInstance)) return false;
1254        return abstractName.equals(((GBeanInstance) obj).abstractName);
1255    }
1256
1257    public int hashCode() {
1258        return abstractName.hashCode();
1259    }
1260
1261    public String JavaDoc toString() {
1262        return abstractName.toString();
1263    }
1264}
1265
Popular Tags