QpidClass.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.management.domain.model;
022 
023 import java.nio.ByteBuffer;
024 import java.util.ArrayList;
025 import java.util.HashMap;
026 import java.util.Iterator;
027 import java.util.List;
028 import java.util.Map;
029 import java.util.UUID;
030 import java.util.Map.Entry;
031 import java.util.concurrent.BlockingQueue;
032 import java.util.concurrent.SynchronousQueue;
033 import java.util.concurrent.TimeUnit;
034 import java.util.concurrent.TimeoutException;
035 
036 import javax.management.Attribute;
037 import javax.management.AttributeList;
038 import javax.management.AttributeNotFoundException;
039 import javax.management.InvalidAttributeValueException;
040 import javax.management.MBeanAttributeInfo;
041 import javax.management.MBeanException;
042 import javax.management.MBeanInfo;
043 import javax.management.MBeanOperationInfo;
044 import javax.management.MBeanRegistration;
045 import javax.management.MBeanServer;
046 import javax.management.ObjectName;
047 import javax.management.ReflectionException;
048 import javax.management.RuntimeOperationsException;
049 
050 import org.apache.qpid.management.Messages;
051 import org.apache.qpid.management.Names;
052 import org.apache.qpid.management.domain.handler.impl.IMethodInvocationListener;
053 import org.apache.qpid.management.domain.handler.impl.InvocationResult;
054 import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
055 import org.apache.qpid.management.domain.model.type.Binary;
056 import org.apache.qpid.management.domain.services.SequenceNumberGenerator;
057 import org.apache.qpid.management.jmx.EntityLifecycleNotification;
058 import org.apache.qpid.management.jmx.OperationHasBeenInvokedNotification;
059 import org.apache.qpid.transport.codec.BBDecoder;
060 import org.apache.qpid.transport.util.Logger;
061 
062 /**
063  * Qpid Class definition.
064  * A type definition for a manageable object.
065  * This class is also responsible to manage incoming obejct instance data (configuration & instrumentation). 
066  * How can we handle data before schema is injected into this class? simply we must retain that data in raw format.
067  * This class has 3 states : 
068  * 1) first state is when schema is not yet injected. In this case the incoming object data is retained as is (in raw format) 
069  * and a schema request is sent;
070  * 2) second state is when schema has been requested but not yet injected. The incoming object data is still retained as is 
071  * (in raw format) 
072  * 3) third state is when schema is injected. Each injection of data will result in an update / create / delete of 
073  * the corresponding object instance. In addition, the first time the state change, the old retained raw data is cnverted in 
074  * object instance(s).
075  */ 
076 class QpidClass extends QpidEntity implements QpidClassMBean 
077 {            
078     /**
079      * State interface for this class definition.
080      * Each state is responsible to handle the injection of the data and / or schema. 
081      
082      @author Andrea Gazzarini
083      */
084     interface State 
085     {    
086         /**
087          * Adds configuration data for the object instance associated to the given object identifier.
088          
089          @param objectId the object identifier.
090          @param rawData the raw configuration data.
091          */
092         void addInstrumentationData (Binary objectId, byte[] rawData);
093 
094         /**
095          * Adds instrumentation data for the object instance associated to the given object identifier.
096          
097          @param objectId the object identifier.
098          @param rawData the raw instrumentation data.
099          */
100         void addConfigurationData (Binary objectId, byte[] rawData);       
101         
102         /**
103          * Inject the schema into this class definition.
104          
105          @param propertyDefinitions
106          @param statisticDefinitions
107          @param methodDefinitions
108          @throws UnableToBuildFeatureException when it's not possibile to parse schema and build the class definition.
109          */
110         public  void  setSchema (
111                 List<Map<String, Object>> propertyDefinitions, 
112                 List<Map<String, Object>> statisticDefinitions,
113                 List<MethodOrEventDataTransferObject> methodDefinitionsthrows UnableToBuildFeatureException;
114     };
115     
116     /**
117      * This is the initial state of every qpid class. 
118      * The class definition instance is created but its schema has not been injected. 
119      * Incoming configuration & instrumentation data will be stored in raw format because we don't know how to 
120      * parse it until the schema arrives.
121      * In addition, this state is responsible (when data arrives) to request its schema.
122      */
123     final State _schemaNotRequested = new State() {
124 
125         /**
126          * Stores the incoming data in raw format and request the schema for this class.
127          * After that a transition to the next state is made.
128          
129          @param objectId the object instance identifier.
130          @param rawData incoming configuration data.
131          */
132         public synchronized void addConfigurationData (Binary objectId, byte[] rawData)
133         {
134             try
135             {
136                 requestSchema();  
137                 _state = _schemaRequestedButNotYetInjected;
138             catch (Exception exception)
139             {
140                 _logger.error(
141                     exception,
142                         Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST, 
143                         _parent.getName(),
144                         _name);
145             finally {
146                 QManManagedObject instance = getObjectInstance(objectId,false);
147                 instance._rawConfigurationData.add(rawData);       
148             }
149         }
150 
151         /**
152          * Stores the incoming data in raw format and request the schema for this class.
153          * After that a transition to the next state is made.
154          
155          @param objectId the object instance identifier.
156          @param rawData incoming instrumentation data.
157          */
158         public synchronized void addInstrumentationData (Binary objectId, byte[] rawData)
159         {
160             try
161             {
162                 requestSchema();  
163                 _state = _schemaRequestedButNotYetInjected;
164             catch (Exception e)
165             {
166                 _logger.error(
167                         Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST, 
168                         _parent.getName(),
169                         _name);
170             finally {
171                 QManManagedObject instance = getObjectInstance(objectId,false);
172                 instance._rawConfigurationData.add(rawData);
173             }
174         }
175 
176         /**
177          * This method only throws an illegal state exception because when a schema arrives 
178          * this state is no longer valid.
179          */
180         public void setSchema (
181                 List<Map<String, Object>> propertyDefinitions,
182                 List<Map<String, Object>> statisticDefinitions, 
183                 List<MethodOrEventDataTransferObject> methodDefinitionsthrows UnableToBuildFeatureException
184         {
185             throw new IllegalStateException("When a schema arrives it's not possible for this class to be in this state.");
186         }
187     };
188     
189     /**
190      * This is the first state of this class definition : the schema is not yet injected so each injection of object data will be 
191      * retained in raw format.
192      */
193     final State _schemaRequestedButNotYetInjected = new State()
194     {
195         /**
196          * Stores the incoming data in raw format.
197          
198          @param objectId the object instance identifier.
199          @param rawData incoming configuration data.
200          */
201         public void addConfigurationData (Binary objectId, byte[] rawData)
202         {
203             QManManagedObject instance = getObjectInstance(objectId,false);
204             instance._rawConfigurationData.add(rawData);
205         }
206 
207         /**
208          * Stores the incoming data in raw format.
209          
210          @param objectId the object instance identifier.
211          @param rawData incoming instrumentation data.
212          */
213         public void addInstrumentationData (Binary objectId, byte[] rawData)
214         {
215             QManManagedObject instance = getObjectInstance(objectId,false);
216             instance._rawInstrumentationData.add(rawData);
217         }
218 
219         /**
220          * When a schema is injected into this defintiion the following should happen :
221          * 1) the incoming schema is parsed and the class definition is built;
222          * 2) the retained raw data is converted into object instance(s)
223          * 3) the internal state of this class changes;
224          
225          * If someting is wrong during that process the schema is not built and the state don't change.
226          */
227         public synchronized void setSchema (
228                 List<Map<String, Object>> propertyDefinitions,
229                 List<Map<String, Object>> statisticDefinitions, 
230                 List<MethodOrEventDataTransferObject> methodDefinitionsthrows UnableToBuildFeatureException
231         {
232                 
233                 MBeanAttributeInfo [] attributesMetadata = new MBeanAttributeInfo[propertyDefinitions.size()+statisticDefinitions.size()];
234                 MBeanOperationInfo [] operationsMetadata = new MBeanOperationInfo[methodDefinitions.size()];
235                 
236                 buildAttributes(propertyDefinitions,statisticDefinitions,attributesMetadata);
237                 buildMethods(methodDefinitions,operationsMetadata);
238                 
239                 _metadata = new MBeanInfo(_name,_name,attributesMetadata,null,operationsMetadata,null);
240 
241                 EntityLifecycleNotification notification = new EntityLifecycleNotification(
242                        EntityLifecycleNotification.SCHEMA_INJECTED_NOTIFICATION_TYPE,
243                        _parent.getName()
244                        _name, 
245                        Names.CLASS,
246                        _objectName);
247                    
248                    sendNotification(notification);
249                 
250                 // Converting stored object instances into JMX MBean and removing raw instance data.
251                 for (Entry<Binary, QManManagedObject> instanceEntry : _objectInstances.entrySet())
252                 {
253                     Binary objectId = instanceEntry.getKey();
254                     QManManagedObject instance = instanceEntry.getValue();
255                     
256                     for (Iterator<byte[]> iterator = instance._rawInstrumentationData.iterator(); iterator.hasNext();)
257                     {
258                         updateInstanceWithInstrumentationData(instance,iterator.next());
259                         iterator.remove();
260                     
261 
262                     for (Iterator<byte[]> iterator = instance._rawConfigurationData.iterator(); iterator.hasNext();)
263                     {
264                         updateInstanceWithConfigurationData(instance, iterator.next());
265                         iterator.remove();
266                     }
267 
268                     registerMBean(instance,_parent.getOwnerId(),_parent.getName(),_name,objectId);
269                 }
270             _state = _schemaInjected;     
271             
272         }
273     };
274     
275     /**
276      * After a schema is built into this definition this is the current state of the class.
277      */
278     final State _schemaInjected = new State()
279     {
280         /**
281          * Updates the configuration state of the object instance associates with the given object identifier.
282          
283          @param objectId the object identifier.
284          @param rawData the configuration data (raw format).
285          */
286         public void addConfigurationData (Binary objectId, byte[] rawData)
287         {
288             QManManagedObject instance = getObjectInstance(objectId,true);            
289             updateInstanceWithConfigurationData(instance, rawData);
290         }
291 
292         /**
293          * Updates the instrumentation state of the object instance associates with the given object identifier.
294          
295          @param objectId the object identifier.
296          @param rawData the instrumentation data (raw format).
297          */
298         public void addInstrumentationData (Binary objectId, byte[] rawData)
299         {
300             QManManagedObject instance = getObjectInstance(objectId,true);            
301             updateInstanceWithInstrumentationData(instance, rawData);
302         }
303 
304         /**
305          * Never called when the class definition has this state.
306          */
307         public void setSchema (
308                 List<Map<String, Object>> propertyDefinitions,
309                 List<Map<String, Object>> statisticDefinitions, 
310                 List<MethodOrEventDataTransferObject> methodDefinitionsthrows UnableToBuildFeatureException
311         {
312             throw new IllegalStateException("When a schema arrives it's not possible for this class to be in this state.");
313         }
314     };
315     
316     /**
317      * MBean used for representing remote broker object instances.
318      * This is the core component of the QMan domain model
319      */
320     class QManManagedObject extends QManManagedEntity implements MBeanRegistration
321     {
322         private Binary _objectId;
323         
324         // Arrays used for storing raw data before this mbean is registered to mbean server.
325         List<byte[]> _rawInstrumentationData = new ArrayList<byte[]>();
326         List<byte[]>  _rawConfigurationData = new ArrayList<byte[]>();
327          
328         /**
329          * Builds a new managed object with the given object identifier.
330          
331          @param objectId the object identifier.
332          */
333         QManManagedObject(Binary objectId)
334         {
335             this._objectId = objectId;
336         }
337         
338         /**
339          * Returns the value of the given attribute.s
340          
341          @throws AttributeNotFoundException when no attribute is found with the given name.
342          */
343         public Object getAttribute (String attributeNamethrows AttributeNotFoundException, MBeanException, ReflectionException
344         {
345             if (attributeName == null
346             {
347                 throw new RuntimeOperationsException(new IllegalArgumentException("attribute name must not be null"));
348             }
349             
350             if (_properties.containsKey(attributeName|| _statistics.containsKey(attributeName))
351             {
352                 return _attributes.get(attributeName);  
353             else 
354             {
355                 throw new AttributeNotFoundException(attributeName);
356             }        
357         }
358 
359         /**
360          * Executes an operation on this object instance.
361          
362          @param actionName the name of the method.
363          @param params the method parameters 
364          @param signature the method signature.
365          */
366         public Object invoke (String actionName, Object[] params, String[] signaturethrows MBeanException,ReflectionException
367         {
368           OperationHasBeenInvokedNotification notification = null;
369           try 
370           {
371               QpidMethod method = _methods.get(actionName);
372               if (method != null
373               {
374                   try
375                   {
376                       method.validate(params);
377                       InvocationResult result = invokeMethod(_objectId, method, params);
378                       notification = new OperationHasBeenInvokedNotification(actionName,params,signature,result);
379                       return result;
380                   catch (Exception ex)
381                   {
382                     MBeanException exception = new MBeanException(ex);
383                       notification = new OperationHasBeenInvokedNotification(actionName,params,signature,exception);
384                       throw exception;
385                   }
386               else 
387               {
388                 ReflectionException exception = new ReflectionException(new NoSuchMethodException(actionName));
389                   notification = new OperationHasBeenInvokedNotification(actionName,params,signature,exception);
390                   throw exception;
391               
392           finally 
393           {
394             sendNotification(notification);
395           }
396         }
397 
398         /**
399          * Sets the value of the given attribute on this object instance.
400          
401          @param attribute contains the new value of the attribute.
402          @throws AttributeNotFoundException when the given attribute is not found on this object instance.
403          @throws InvalidAttributeValueException when the given value is violating one attribute invariant.
404          */
405         public void setAttribute (Attribute attributethrows AttributeNotFoundException,
406                 InvalidAttributeValueException, MBeanException, ReflectionException
407         {
408             QpidProperty property = _properties.get(attribute.getName());
409             try 
410             {
411                 property.validate(attribute.getValue());
412             catch(ValidationException exception
413             {
414                 throw new InvalidAttributeValueException(exception.getMessage());
415             }
416             throw new RuntimeException("Not yet implemented.");
417         }
418 
419         /**
420          * Sets the values of several attributes of this MBean.
421          *
422          @param attributes a list of attributes: The identification of the attributes to be set and the values they are to be set to.
423          @return  The list of attributes that were set, with their new values.
424          */
425         public AttributeList setAttributes (AttributeList attributes)
426         {
427             throw new RuntimeException("Not yet implemented.");
428         }
429 
430         /**
431          * MBean server callback after deregistration.
432          */
433         public void postDeregister ()
434         {
435         }
436 
437         /**
438          * After the object is registered the raw data is set to null.
439          * This is done because we no longer need this data : it has already been 
440          * injected into this object instance.
441          
442          @param registrationDone a flag indicating if the instance has been registered to mbean server.
443          */
444         public void postRegister (Boolean registrationDone)
445         {
446             if (registrationDone
447             {
448                 _rawConfigurationData = null;
449                 _rawInstrumentationData = null;
450             }
451         }
452 
453         /**
454          * MBean server callback before deregistration.
455          */
456         public void preDeregister () throws Exception
457         {
458         }
459         
460         /**
461          * MBean server callback before registration.
462          */
463         public ObjectName preRegister (MBeanServer server, ObjectName namethrows Exception
464         {
465             return name;
466         }
467     }
468     
469     Map<String, QpidProperty> _properties = new HashMap<String, QpidProperty>()
470     Map<String, QpidStatistic> _statistics = new HashMap<String, QpidStatistic>();
471     private Map<String, QpidMethod> _methods = new HashMap<String, QpidMethod>();
472     
473     private List<QpidProperty> _schemaOrderedProperties = new ArrayList<QpidProperty>();
474     private List<QpidStatistic> _schemaOrderedStatistics= new ArrayList<QpidStatistic>();
475     
476     private int _howManyPresenceBitMasks;
477     private BlockingQueue<InvocationResult> _exchangeChannelForMethodInvocations;
478     private final IMethodInvocationListener _methodInvocationListener;
479     
480     Map<Binary, QManManagedObject> _objectInstances = new HashMap<Binary, QManManagedObject>();
481     State _state = _schemaNotRequested;;
482     
483     private final static class Log 
484     {
485       private final static Logger LOGGER = Logger.get(QpidClass.class);
486         final static void logMethodInvocationResult(InvocationResult result)
487         {
488             if (LOGGER.isDebugEnabled())
489             {
490                 LOGGER.debug(String.valueOf(result));
491             }
492         }
493     }
494     
495     /**
496      * Builds a new class with the given name and package as parent.
497      
498      @param className the name of the class.
499      @param hash the class schema hash.
500      @param parentPackage the parent of this class.
501      */
502     QpidClass(String className, Binary hash, QpidPackage parentPackage)
503     {
504       super(className,hash, parentPackage,Names.CLASS);
505         this._methodInvocationListener = _parent.getMethodInvocationListener();
506         this._exchangeChannelForMethodInvocations = new SynchronousQueue<InvocationResult>();
507     }
508     
509     /**
510      * Adds the configuration data for the object instance associated to the given object identifier.
511      
512      @param objectId the object identifier.
513      @param rawData the raw configuration data.
514      */
515     void addInstrumentationData (Binary objectId, byte[] rawData)
516     {
517         _logger.debug(
518             Messages.QMAN_200014_INCOMING_INSTRUMENTATION_DATA,
519                 _parent.getOwnerId(),
520                 _parent.getName(),
521                 _name,
522                 objectId);        
523         _state.addInstrumentationData(objectId, rawData);
524     }
525     
526     /**
527      * Adds the instrumentation data for the object instance associated to the given object identifier.
528      
529      @param objectId the object identifier.
530      @param rawData the raw instrumentation data.
531      */
532     void addConfigurationData (Binary objectId, byte[] rawData)
533     {
534         _logger.debug(
535             Messages.QMAN_200015_INCOMING_CONFIGURATION_DATA,
536                 _parent.getOwnerId(),
537                 _parent.getName(),
538                 _name,
539                 objectId);        
540         _state.addConfigurationData(objectId, rawData);
541     }
542 
543     /**
544      * Sets the schema for this class definition. 
545      * A schema is basically a metadata description of all properties, statistics, methods and events of this class.
546      
547      @param propertyDefinitions properties metadata.
548      @param statisticDefinitions statistics metadata.
549      @param methodDefinitions methods metadata.
550      @throws UnableToBuildFeatureException when some error occurs while parsing the incoming schema.
551      */
552      void setSchema (
553             List<Map<String, Object>> propertyDefinitions, 
554             List<Map<String, Object>> statisticDefinitions,
555             List<MethodOrEventDataTransferObject> methodDefinitionsthrows UnableToBuildFeatureException
556     {
557          _logger.info(Messages.QMAN_000010_INCOMING_SCHEMA,_parent.getOwnerId(),_parent.getName(),_name);
558         _state.setSchema(propertyDefinitions, statisticDefinitions, methodDefinitions);
559     }    
560 
561     /**
562      * Internal method used for building attributes definitions.
563      
564      @param props the map contained in the properties schema.
565      @param stats the map contained in the statistics schema.
566      @param attributes the management metadata for attributes.
567      @throws UnableToBuildFeatureException  when it's not possibile to build one attribute definition.
568      */
569     void buildAttributes (
570             List<Map<String, Object>> props,
571             List<Map<String, Object>> stats,
572             MBeanAttributeInfo[] attributesthrows UnableToBuildFeatureException
573     {
574         int index = 0;
575         int howManyOptionalProperties = 0;
576         
577         for (Map<String, Object> propertyDefinition : props)
578         {
579             QpidFeatureBuilder builder = QpidFeatureBuilder.createPropertyBuilder(propertyDefinition);
580             builder.build();
581             
582             QpidProperty property = (QpidPropertybuilder.getQpidFeature();           
583             
584             howManyOptionalProperties += (property.isOptional()) 0;
585             
586             _properties.put(property.getName(),property);
587             _schemaOrderedProperties.add(property);
588             attributes[index++]=(MBeanAttributeInfobuilder.getManagementFeature();
589             
590             _logger.debug(
591                     Messages.QMAN_200016_PROPERTY_DEFINITION_HAS_BEEN_BUILT,
592                     _parent.getName(),
593                     _name,
594                     property);
595         }
596                 
597         _howManyPresenceBitMasks =  (int)Math.ceil((double)howManyOptionalProperties / 8);
598         
599         _logger.debug(
600                 Messages.QMAN_200018_OPTIONAL_PROPERTIES_INFO,
601                 _parent.getOwnerId(),
602                 _parent.getName(),
603                 _name,
604                 _howManyPresenceBitMasks);
605         
606         for (Map<String, Object> statisticDefinition : stats)
607         {
608             QpidFeatureBuilder builder = QpidFeatureBuilder.createStatisticBuilder(statisticDefinition);
609             builder.build();
610             QpidStatistic statistic = (QpidStatisticbuilder.getQpidFeature();
611             
612             _statistics.put(statistic.getName(),statistic);
613             _schemaOrderedStatistics.add(statistic);
614             attributes[index++]=(MBeanAttributeInfobuilder.getManagementFeature();
615             
616             _logger.debug(
617                     Messages.QMAN_200017_STATISTIC_DEFINITION_HAS_BEEN_BUILT,
618                     _parent.getName(),
619                     _name,
620                     statistic);            
621         }
622     }    
623     
624     /**
625      * Returns the object instance associated to the given identifier.
626      * Note that if the identifier is not associated to any obejct instance, a new one will be created.
627      
628      @param objectId the object identifier.
629      @param registration a flag indicating whenever the (new ) instance must be registered with MBean server.
630      @return the object instance associated to the given identifier.
631      */
632     QManManagedObject getObjectInstance(Binary objectId, boolean registration
633     {
634         QManManagedObject objectInstance = _objectInstances.get(objectId);
635         if (objectInstance == null
636         {
637             objectInstance = new QManManagedObject(objectId);
638             _objectInstances.put(objectId, objectInstance);
639             if (registration)
640             {
641               registerMBean(objectInstance,_parent.getOwnerId(),_parent.getName(),_name,objectId);
642             }
643         }
644         return objectInstance;
645     }
646     
647     /**
648      * Internal method used for building method defintiions.
649      
650      @param definitions the properties map contained in the incoming schema.
651      @param operationsMetadata 
652      @throws UnableToBuildFeatureException  when it's not possibile to build one or more definitions.
653      */
654     void buildMethods (List<MethodOrEventDataTransferObject> definitions, MBeanOperationInfo[] operationsMetadatathrows UnableToBuildFeatureException
655     {
656         int index = 0;
657         for (MethodOrEventDataTransferObject definition: definitions)
658         {
659             QpidFeatureBuilder builder = QpidFeatureBuilder.createMethodBuilder(definition);
660             builder.build();
661             operationsMetadata [index++](MBeanOperationInfobuilder.getManagementFeature()
662             QpidMethod method = (QpidMethodbuilder.getQpidFeature();
663             _methods.put(method.getName(),method);
664         }
665     }    
666     
667     /**
668      * Header (opcode='M') 
669      * ObjectId of target object (128 bits) 
670      * Package name (str8) 
671      * Class name (str8) 
672      * Class hash (bin128) 
673      * Method name (str8) [as defined in the schema] 
674      * Now encode all input ("I") and i/o (IO) arguments in the order in which they are defined in the schema. 
675      * (i.e. make one pass over the argument list and encode arguments that are either input or inptu/output). 
676 
677      @param objectId
678      @param method
679      @param parameters
680      @throws Exception
681      */
682     private InvocationResult invokeMethod(Binary objectId,QpidMethod method,Object [] parametersthrows Exception
683     {
684         try
685         {
686             _service.connect();
687             
688             int sequenceNumber = SequenceNumberGenerator.getNextSequenceNumber();
689             _methodInvocationListener.operationIsGoingToBeInvoked(new InvocationEvent(this,sequenceNumber,_exchangeChannelForMethodInvocations));
690            _service.invoke(_parent.getName(), _name, _hash,objectId,parameters, method,sequenceNumber,objectId.getBankId(),objectId.getBrokerId());
691              
692             InvocationResult result = _exchangeChannelForMethodInvocations.poll(5000,TimeUnit.MILLISECONDS);
693             
694             if (result == null
695             {
696               throw new TimeoutException();
697             }
698             
699             Map<String, Object> output = method.decodeParameters(result.getOutputAndBidirectionalArgumentValues());
700             result.setOutputSection(output);
701             
702             Log.logMethodInvocationResult(result);
703             
704             if (result.isException()) 
705             {
706                 result.createAndThrowException();
707             }
708             return result;
709         finally
710         {
711             _service.close();
712         }                
713     }
714     
715     /**
716      * Updates the given obejct instance with the given incoming configuration data.
717      
718      @param instance the managed object instance.
719      @param rawData the incoming configuration data which contains new values for instance properties.
720      */
721     void updateInstanceWithConfigurationData(QManManagedObject instance,byte [] rawData)
722     {
723         BBDecoder decoder = new BBDecoder();
724         decoder.init(ByteBuffer.wrap(rawData));
725 
726         byte [] presenceBitMasks = decoder.readBytes(_howManyPresenceBitMasks);
727         for (QpidProperty property : _schemaOrderedProperties)
728         {                  
729             try {
730                 Object value = property.decodeValue(decoder,presenceBitMasks);
731                 instance.createOrReplaceAttributeValue(property.getName(),value);             
732             catch(Exception ignore) {
733                 _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,property.getName());
734             }
735         }
736     }
737     
738     /**
739      * Updates the given object instance with the given incoming instrumentation data.
740      
741      @param instance the managed object instance.
742      @param rawData the incoming instrumentation data which contains new values for instance properties.
743      */
744     void updateInstanceWithInstrumentationData(QManManagedObject instance,byte [] rawData)
745     {
746       BBDecoder decoder = new BBDecoder();
747         decoder.init(ByteBuffer.wrap(rawData));
748 
749         for (QpidStatistic statistic : _schemaOrderedStatistics)
750         {                  
751             try {
752                 Object value = statistic.decodeValue(decoder);
753                 instance.createOrReplaceAttributeValue(statistic.getName(),value);             
754             catch(Exception ignore) {
755                 _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,statistic.getName());
756             }
757         }
758     }    
759     
760     @Override
761     public String toString ()
762     {
763         return new StringBuilder()
764             .append(_parent.getOwnerId())
765             .append("::")
766             .append(_parent.getName())
767             .append('.')
768             .append(_name)
769             .toString();
770     }
771 
772     /**
773      * Removes the object instance associated to the given identifier.
774      
775      @param objectId the object identifier.
776      */
777     void removeObjectInstance (Binary objectId)
778     {
779         QManManagedObject toBeRemoved = _objectInstances.remove(objectId);
780         if (toBeRemoved != null)
781         {
782             ObjectName objectName = JMX_SERVICE.unregisterObjectInstance(_parent.getOwnerId(),_parent.getName(),_name,toBeRemoved._objectId);
783             
784           EntityLifecycleNotification notification = new EntityLifecycleNotification(
785            EntityLifecycleNotification.INSTANCE_REMOVED_NOTIFICATION_TYPE,
786            _parent.getName(),
787            _name,
788            Names.CLASS,
789            objectName);
790        
791        sendNotification(notification);
792         }
793     }
794 
795     /**
796      * Deregisters all the object instances and release all previously acquired resources.
797      */
798     void releaseResources ()
799     {
800       _objectInstances.clear();
801       JMX_SERVICE.unregisterObjectInstances();
802       JMX_SERVICE.unregisterClassDefinitions();      
803         _service.close();
804     }
805     
806     /**
807      * Compose method used for registering mbean instance.
808      
809      @param instance the mbean instance.
810      @param brokerId the broker identifier.
811      @param packageName the package name.
812      @param className the class name.
813      @param objectId the object identifier.
814      */
815     private void registerMBean(
816         QManManagedObject instance,
817             UUID brokerId,
818             String packageName, 
819             String className, 
820             Binary objectId)
821     {
822        ObjectName objectName = JMX_SERVICE.registerObjectInstance(instance,_parent.getOwnerId(),_parent.getName(),_name,objectId);
823        
824        EntityLifecycleNotification notification = new EntityLifecycleNotification(
825            EntityLifecycleNotification.INSTANCE_ADDED_NOTIFICATION_TYPE,
826            packageName,
827            className,
828            Names.CLASS,
829            objectName);
830        
831        sendNotification(notification);
832     }
833 }