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> methodDefinitions) throws 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> methodDefinitions) throws 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> methodDefinitions) throws 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> methodDefinitions) throws 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 attributeName) throws 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[] signature) throws 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 attribute) throws 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 name) throws 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> methodDefinitions) throws 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[] attributes) throws 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 = (QpidProperty) builder.getQpidFeature();
583
584 howManyOptionalProperties += (property.isOptional()) ? 1 : 0;
585
586 _properties.put(property.getName(),property);
587 _schemaOrderedProperties.add(property);
588 attributes[index++]=(MBeanAttributeInfo) builder.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 = (QpidStatistic) builder.getQpidFeature();
611
612 _statistics.put(statistic.getName(),statistic);
613 _schemaOrderedStatistics.add(statistic);
614 attributes[index++]=(MBeanAttributeInfo) builder.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[] operationsMetadata) throws UnableToBuildFeatureException
655 {
656 int index = 0;
657 for (MethodOrEventDataTransferObject definition: definitions)
658 {
659 QpidFeatureBuilder builder = QpidFeatureBuilder.createMethodBuilder(definition);
660 builder.build();
661 operationsMetadata [index++]= (MBeanOperationInfo) builder.getManagementFeature();
662 QpidMethod method = (QpidMethod) builder.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 [] parameters) throws 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 }
|