QpidFeatureBuilder.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.util.ArrayList;
024 import java.util.LinkedList;
025 import java.util.List;
026 import java.util.Map;
027 import java.util.Map.Entry;
028 
029 import javax.management.MBeanAttributeInfo;
030 import javax.management.MBeanFeatureInfo;
031 import javax.management.MBeanOperationInfo;
032 import javax.management.MBeanParameterInfo;
033 
034 import org.apache.qpid.management.configuration.Configuration;
035 import org.apache.qpid.management.configuration.UnknownTypeCodeException;
036 import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject;
037 import org.apache.qpid.management.Names;
038 
039 /**
040  * A builder used to parse incoming schema message and therefore to build a feature (property, statistic, method, event)
041  * definition.
042  * In order to set up the correct state for this builder, clients must create an instance of this class
043  * The product of the builder will be a QpidFeature and a  JMX Managemtn feature used for describing that feature in a 
044  * JMX environment. So, for example, for building a property definition client code should be :
045  
046  <br>- QpidFeatureBuilder builder = QpidFeature.createPropertyBuilder(...);
047  <br>- builder.build();
048  <br>- QpidProperty property = (QpidProperty) builder.getQpidFeature();
049  <br>- MBeanAttributeInfo managementAttributeInfo = (MBeanAttributeInfo)builder.getManagementFeature();
050  
051  <br>N.B.: a builder instance is not supposed to be reused. One instance for one feature!
052  
053  @author Andrea Gazzarini
054  */
055 class QpidFeatureBuilder
056 {
057     
058     static enum Attribute {
059         name,type,access,index,optional,unit,min,max,maxlen,desc,dir,argCount;
060     };
061     
062     private List<Attribute> _mandatoryAttributes = new ArrayList<Attribute>();
063     
064     /**
065      * Builder state for this class.
066      * Each concrete implementor is a builder for a specific feature. 
067      * using the appropriate factory method.
068      
069      @author Andrea Gazzarini
070      */
071     interface State {
072         void build() throws UnableToBuildFeatureException;
073     }
074     
075     /**
076      * Builder used for building property definition.
077      */
078     final State _propertyBuilder = new State() {
079 
080         /**
081          * Builds a property definition as well a management attribute feature.
082          */
083         public void build () throws UnableToBuildFeatureException
084         {
085             QpidProperty property = new QpidProperty();
086             try {         
087                 int optionalIndex = 0;
088                 for (Entry<String, Object> propertyAttribute : _featureDefinition.entrySet())
089                 {
090                     Attribute attribute = Attribute.valueOf(propertyAttribute.getKey());
091                     switch(attribute)
092                     {
093                         case name : 
094                         {
095                             property.setName(String.valueOf(propertyAttribute.getValue()));       
096                             break;
097                         }
098                         case access : 
099                         {
100                             int code = (Integer)propertyAttribute.getValue();
101                             property.setAccessMode(Configuration.getInstance().getAccessMode(code))
102                             break;
103                         }
104                         case unit :
105                         {
106                             property.setUnit(String.valueOf(propertyAttribute.getValue()));
107                             break;                        
108                         }
109                         case min :
110                         {
111                             property.setMinValue((Integer)propertyAttribute.getValue());
112                             break;                        
113                         }
114                         case max :
115                         {
116                             property.setMaxValue((Integer)propertyAttribute.getValue());
117                             break;                        
118                         }
119                         case maxlen :
120                         {
121                             property.setMaxLength((Integer)propertyAttribute.getValue());
122                             break;                        
123                         }
124                         case desc :
125                         {
126                             property.setDescription(String.valueOf(propertyAttribute.getValue()));
127                             break;                        
128                         }
129                         case type : 
130                         {
131                             int code = (IntegerpropertyAttribute.getValue();
132                             property.setType(Configuration.getInstance().getType(code));
133                             break;
134                         }
135                         case index : 
136                         {
137                             break;
138                         }
139                         case optional : 
140                         {
141                             int code = (IntegerpropertyAttribute.getValue();
142                             if (code == 1)
143                             {
144                                 property.markAsOptional(optionalIndex);
145                                 optionalIndex++;
146                             
147                             break;
148                         }                    
149                     }
150                     _mandatoryAttributes.remove(attribute);
151                 }                
152             catch(Exception exception
153             {
154                 throw new UnableToBuildFeatureException(exception,property.getName());
155             
156             
157             if (!_mandatoryAttributes.isEmpty())
158             {
159                 throw new MissingFeatureAttributesException(_mandatoryAttributes);
160             }
161             
162             _managementFeatureInfo = new MBeanAttributeInfo(
163                     property.getName(),
164                     property.getJavaType().getName(),
165                     property.getDescription(),
166                     true,
167                     property.getAccessMode()==AccessMode.RW,
168                     false);
169             _qpidFeature = property;
170         }
171     };
172     
173     final State _statisticBuilder = new State()
174     {
175         public void build () throws UnableToBuildFeatureException
176         {
177             QpidStatistic statistic = new QpidStatistic();
178             try 
179             {
180                 for (Entry<String, Object> statisticAttribute : _featureDefinition.entrySet())
181                 {
182                     Attribute attribute = Attribute.valueOf(statisticAttribute.getKey());
183                     switch(attribute)
184                     {
185                         case name : 
186                         {
187                             statistic.setName(String.valueOf(statisticAttribute.getValue()));
188                             break;
189                         }
190                         case unit :
191                         {
192                             statistic.setUnit(String.valueOf(statisticAttribute.getValue()));
193                             break;                        
194                         }
195                         case desc :
196                         {
197                             statistic.setDescription(String.valueOf(statisticAttribute.getValue()));
198                             break;                        
199                         }
200                         case type : 
201                         {
202                             int code = (IntegerstatisticAttribute.getValue();
203                             statistic.setType(Configuration.getInstance().getType(code));
204                             break;
205                         }
206                    }
207                     _mandatoryAttributes.remove(attribute);
208                 }
209             catch(Exception exception
210             {
211                 throw new UnableToBuildFeatureException(exception,statistic.getName());
212             }            
213             
214             if (!_mandatoryAttributes.isEmpty())
215             {
216                 throw new MissingFeatureAttributesException(_mandatoryAttributes);
217             }
218             
219             _managementFeatureInfo = new MBeanAttributeInfo(
220                     statistic.getName(),
221                     statistic.getJavaType().getName(),
222                     statistic.getDescription(),
223                     true,
224                     false,
225                     false);
226             _qpidFeature = statistic;
227         }
228     };
229         
230     /**
231      * Builder used for building a statistic definition.
232      */
233     final State _argumentBuilder = new State()
234     {
235         /**
236          * Builds a property definition as well a management attribute feature.
237          */
238         public void build () throws UnableToBuildFeatureException
239         {
240             QpidArgument argument = new QpidArgument();
241             for (Entry<String, Object> argumentAttribute : _featureDefinition.entrySet())
242             {
243                 String key = argumentAttribute.getKey();
244                 if (Names.DEFAULT_PARAM_NAME.equals(key))
245                 {
246                     argument.setDefaultValue(argumentAttribute.getValue());
247                 else {
248                     Attribute attribute = Attribute.valueOf(key);
249                     switch (attribute)
250                     {
251                         case name :
252                         {
253                             argument.setName((String)argumentAttribute.getValue());
254                             break;
255                         }
256                         case desc :
257                         {
258                             argument.setDescription((String)argumentAttribute.getValue());
259                             break;
260                         }
261                         case type :
262                         {
263                             try 
264                             {
265                                 argument.setType(Configuration.getInstance().getType((Integer)argumentAttribute.getValue()));
266                                 break;
267                             catch(UnknownTypeCodeException exception)
268                             {
269                                 throw new UnableToBuildFeatureException(exception,argument.getName());                                
270                             }
271                         }
272                         case dir : 
273                         {
274                             argument.setDirection((String)argumentAttribute.getValue());                            
275                             break;
276                         }
277                         case unit : 
278                         {
279                             argument.setUnit((String)argumentAttribute.getValue());
280                             break;
281                             
282                         }
283                     }
284                 }
285             }
286             
287             if (!_mandatoryAttributes.isEmpty())
288             {
289                 throw new MissingFeatureAttributesException(_mandatoryAttributes);
290             }
291             
292             _qpidFeature = argument;
293             _managementFeatureInfo = new MBeanParameterInfo(
294                     argument.getName()
295                     argument.getJavaType().getName(),
296                     argument.getDescription());            
297         }  
298     };
299     
300     final State _methodBuilder = new State()
301     {
302         public void build () throws UnableToBuildFeatureException
303         {
304             Map<String,Object> definition = _methodOrEventDefinition.getDefinition();
305             String name = (String)definition.get(Attribute.name.name());
306             if (name == null)
307             {
308                 throw new MissingFeatureAttributesException(_mandatoryAttributes);
309             }
310             
311             QpidMethod method = new QpidMethod((String)definition.get(Attribute.name.name()),(Stringdefinition.get(Attribute.desc.name()));
312 
313             List<Map<String,Object>> args = _methodOrEventDefinition.getArgumentsDefinitions();            
314             
315             List<MBeanParameterInfo> signature = new LinkedList<MBeanParameterInfo>();
316             
317             for (Map<String,Object> argumentDefinition : args)
318             {
319                 QpidFeatureBuilder builder = QpidFeatureBuilder.createArgumentBuilder(argumentDefinition);
320                 builder.build();
321 
322                 QpidArgument argument = (QpidArgumentbuilder.getQpidFeature();
323                 method.addArgument(argument);
324                 if (argument.isInput())
325                 {
326                     signature.add((MBeanParameterInfobuilder.getManagementFeature());
327                 }
328             }    
329 
330             _qpidFeature = method;
331             _managementFeatureInfo = new MBeanOperationInfo(
332                   method.getName(),
333                   method.getDescription(),
334                   (MBeanParameterInfo[])signature.toArray(new MBeanParameterInfo[signature.size()]),
335                   void.class.getName(),
336                   MBeanOperationInfo.ACTION);
337         }
338     };
339 
340     final State _eventBuilder = new State()
341     {
342         public void build () throws UnableToBuildFeatureException
343         {
344         }
345     };
346     
347     private MBeanFeatureInfo _managementFeatureInfo;
348     private QpidFeature _qpidFeature;
349     private final Map <String, Object> _featureDefinition;
350     private final MethodOrEventDataTransferObject _methodOrEventDefinition;
351     private State _state;
352     
353     static QpidFeatureBuilder createPropertyBuilder(Map<String, Object> propertyDefinition)
354     {
355         QpidFeatureBuilder result = new QpidFeatureBuilder(propertyDefinition);
356         result._state = result._propertyBuilder;
357         result._mandatoryAttributes.add(Attribute.name);
358         result._mandatoryAttributes.add(Attribute.access);
359         result._mandatoryAttributes.add(Attribute.type);
360         result._mandatoryAttributes.add(Attribute.optional);
361         result._mandatoryAttributes.add(Attribute.index);
362         return result;
363     }
364 
365     static QpidFeatureBuilder createStatisticBuilder(Map<String, Object> statisticDefinition)
366     {
367         QpidFeatureBuilder result = new QpidFeatureBuilder(statisticDefinition);
368         result._state = result._statisticBuilder;
369         result._mandatoryAttributes.add(Attribute.name);
370         result._mandatoryAttributes.add(Attribute.type);
371         return result;
372     }
373 
374     static QpidFeatureBuilder createEventBuilder(Map<String, Object> eventDefinition)
375     {
376         QpidFeatureBuilder result = new QpidFeatureBuilder(eventDefinition);
377         result._state = result._eventBuilder;
378         return result;
379     }
380 
381     static QpidFeatureBuilder createMethodBuilder(MethodOrEventDataTransferObject methodDefinition)
382     {
383         QpidFeatureBuilder result = new QpidFeatureBuilder(methodDefinition);
384         result._state = result._methodBuilder;
385         result._mandatoryAttributes.add(Attribute.name)
386         return result;
387     }
388 
389     private static QpidFeatureBuilder createArgumentBuilder(Map<String, Object> argumentDefinition)
390     {
391         QpidFeatureBuilder result = new QpidFeatureBuilder(argumentDefinition);
392         result._state = result._argumentBuilder;
393         return result;
394     }
395 
396     
397     /**
398      * Builds new builder with the given data.
399      * This constructor is used for building properties, statistics and arguments.
400      
401      @param definition the feature definition data.
402      */
403     private QpidFeatureBuilder(Map<String, Object> definition
404     {
405         this._featureDefinition = definition;
406         this._methodOrEventDefinition = null;
407     }    
408 
409     /**
410      * Builds new builder with the given data.
411      * This constructor is used for building properties, statistics and arguments.
412      
413      @param definition the feature definition data.
414      */
415     private QpidFeatureBuilder(MethodOrEventDataTransferObject definition
416     {
417         this._featureDefinition = null;
418         this._methodOrEventDefinition = definition;
419     }    
420     
421     /**
422      * Returns the just built qpid feature.
423      *  
424      @return the qpid feature.
425      */
426     QpidFeature getQpidFeature() 
427     {
428         return _qpidFeature;
429     }
430     
431     /**
432      * Return the jmx metadata for the built feature.
433      
434      @return the jmx metadata for the built feature.
435      */
436     MBeanFeatureInfo getManagementFeature()
437     {
438         return _managementFeatureInfo;
439     }
440     
441     void build() throws UnableToBuildFeatureException
442     {
443       try 
444       {
445         _state.build();
446       catch(UnableToBuildFeatureException exception)
447       {
448         throw exception;
449       catch(Exception exception)
450       {
451         throw new UnableToBuildFeatureException(exception,"Feature name is not available for debugging.");
452       }
453     }
454 }