def __init__(self): # Logger self._log = Logger.get_instance() # ConfigObj reference self._parser = None # System configuration parser self._system_parser = SystemParser() # Service parser factory self._factory_service_parser = FactoryServiceParser.get_instance() # The service specific parser self._service_parser = None # The factories for the creation of extractors and collectors self._factory_extractor = FactoryExtractor.get_instance() self._factory_collector = FactoryCollector.get_instance() # All services expressed in the configuration file. Each service is an instance of model.service.Service self._services = []
class Parser(object): def __init__(self): # Logger self._log = Logger.get_instance() # ConfigObj reference self._parser = None # System configuration parser self._system_parser = SystemParser() # Service parser factory self._factory_service_parser = FactoryServiceParser.get_instance() # The service specific parser self._service_parser = None # The factories for the creation of extractors and collectors self._factory_extractor = FactoryExtractor.get_instance() self._factory_collector = FactoryCollector.get_instance() # All services expressed in the configuration file. Each service is an instance of model.service.Service self._services = [] def __repr__(self): return "Parser[ComparisonFramework]" ''' Return the list of all services defined in the configuration file. ''' def get_services(self): return self._services ''' This method has in charge the task of parsing the configuration file. ''' def parse(self, config_file): # First of all, run the SystemParser self._system_parser.parse() # Load the configuration file configuration_file = os.path.abspath(config_file) self._log.debug(self.__class__.__name__, 'Checking if config file %s exists.', configuration_file) if os.path.isfile(configuration_file): self._log.info(self.__class__.__name__, 'Loading configuration from %s.', configuration_file) # Take the absolute path of the configuration file self._parser = ConfigObj(infile=configuration_file) else: self._log.error(self.__class__.__name__, 'File %s does not exist; please try again with a valid configuration file.', config_file) sys.exit(-1) ''' Starting to load services ''' self._log.debug(self.__class__.__name__, 'Loading services.') framework = self._parser['Framework'] # Variable services contains all services declared in the framework input file corresponding to the section # [Framework] services = framework['services'] ''' Check if configuration file just contains one service or more. Here the problem is that ConfigObj returns a string if the value of a key is just an element; it returns a list otherwise. In the former case, transform it as a string ''' if not isinstance(services, list): s = services services = [s] # Now services list contains all services' name as strings # Check if all services declared into framework.cfg are valid. self._check_services(services) # Load association between alternatives and environments (note that an alternative can be ran in more than one # environment self._log.debug(self.__class__.__name__, 'Loading environments.') ''' For each service, create a Service object with its alternatives and metrics. Here I'm sure that the service is valid (it has been already checked). ''' for service_name in services: # Replace space that may be present in the service name service_name = service_name.replace(' ', '') self._log.debug(self.__class__.__name__, 'Service %s is available: create the specific parser.', service_name) # Create the specialized service parser service_parser = self._system_parser.get_service_parser(service_name) self._service_parser = self._factory_service_parser.create_service_parser(service_parser, service_name) self._log.info(self.__class__.__name__, 'Specialized service parser %s has been created.', self._service_parser) # Create the service. Variable s contains an instance of class model.service.Service service = self._service_parser.create_service() ''' Load alternatives and metrics based on this service name ''' # service_block is the piece of configuration file containing all stuff related to a service service_block = self._parser[service_name] # Take alternatives and metrics for this service self._log.debug(self.__class__.__name__, 'Loading alternatives for service %s.', service_name) alternatives = service_block['alternatives'] # If the alternative is just one, the ConfigObj does not return a list, but a single object: transform # it into a list if not isinstance(alternatives, list): alternatives = [alternatives] self._log.debug(self.__class__.__name__, 'Loading metrics for service %s.', service_name) metrics = service_block['metrics'] # If the metric is just one, the ConfigObj does not return a list, but a single object: transform it # into a list if not isinstance(metrics, list): metrics = [metrics] self._log.debug(self.__class__.__name__, 'Loading scenario for service %s.', service_name) # Load scenario based on the section 'Scenario' of this service # s is an instance of class Service; service is the "configuration block" of the configuration file # from which retrieve other configuration information (like alternatives) and alternatives is the list # of alternatives declared in the [Service] section in the configuration file. self._handle_alternative_and_metric_for_service(service, service_block, alternatives, metrics) ''' Service has been correctly created: add in to the list of all services ''' self._services.append(service) self._log.info(self.__class__.__name__, 'New service has been created: %s.', s) ''' Check if all services' names are valid. ''' def _check_services(self, services): for service in services: if not self._system_parser.service_is_valid(service): self._log.error(self.__class__.__name__, 'Service %s is not a valid service; please check its name.', service) sys.exit(-1) ''' Check if the association between alternative and environment specified as parameters is correct in accord with the associations declared into the file system.xml. Actually, this method also checks if alternatives and environments are valid in accord with the system.xml file. ''' def _check_mapping_alternative_to_environment(self, alternative, environment): # Check alternative name if not self._system_parser.alternative_is_valid(alternative): self._log.error(self.__class__.__name__, 'Alternative %s is not a valid alternative; please check its name', alternative) sys.exit(-1) # Check environment name if not self._system_parser.environment_is_valid(environment): self._log.error(self.__class__.__name__, 'Environment %s is not a valid environment; please check its name', environment) sys.exit(-1) # Now, check if mapping between alternative and environment is correct. if self._system_parser.mapping_alternative_to_environment_is_valid(alternative, environment): self._log.error( self.__class__.__name__, 'Alternative %s cannot be executed into environment %s; please check your configuration file.', alternative, environment) sys.exit(-1) ''' This method has in charge the task of creating alternative objects for the service passed as parameter; moreover, on that alternative, it has also in charge the task of creating the corresponding scenario ''' def _handle_alternative_and_metric_for_service(self, service, service_block, alternatives, metrics): for alternative_name in alternatives: # Load the specific scenario for the current alternative scenario_parameters = service_block[alternative_name] # For each alternative, take the adapter and create the alternative object (represented by adapter in # system.xml) # Take the adapter for the current alternative alternative_adapter = self._system_parser.get_alternative_adapter(alternative_name) alternative = service.create_alternative(alternative_name, alternative_adapter, scenario_parameters) self._log.info(self.__class__.__name__, 'Alternative %s has been created.', alternative_name) # Based on the content of self._environments parsed from configuration file, set the class name of the # environment to the alternative object environment_name = scenario_parameters['environment'] # Check the correctness of the association between alternative and environment self._check_mapping_alternative_to_environment(alternative_name, environment_name) self._log.info(self.__class__.__name__, 'Environment %s is valid for alternative %s.', environment_name, alternative_name) environment = self._system_parser.get_environment_adapter(environment_name) alternative.set_environment(environment) self._log.info(self.__class__.__name__, 'Environment %s has been associated to alternative %s.', environment_name, alternative_name) # Now, for each alternative, handle metrics self._handle_metrics_for_alternative(alternative, environment_name, metrics) ''' This method has in charge the task of creating metric objects alternative passed as parameter. ''' def _handle_metrics_for_alternative(self, alternative, environment, metrics): for metric_name in metrics: self._log.info(self.__class__.__name__, 'Loading metric %s.', metric_name) # Load the extractor and collector adapters. They are strings, because the extractor and collector are based # both on the metric and the environment to use extractor_adapter = self._system_parser.get_extractor_adapter(metric_name) # Load the actual adapter, based on this metric and the environment for the selected alternative extractor_class = self._factory_extractor.create_extractor(extractor_adapter, environment) self._log.info(self.__class__.__name__, 'Extractor %s has been created.', extractor_adapter) collector_adapter = self._system_parser.get_collector_adapter(metric_name) if collector_adapter is not None: collector_class = self._factory_collector.create_collector(collector_adapter, environment) self._log.info(self.__class__.__name__, 'Collector %s has been created.', collector_adapter) else: collector_class = None self._log.info(self.__class__.__name__, 'Extractor %s does not need any collectors.', extractor_adapter) # Create the metric metric = Metric(metric_name, collector_class, extractor_class) self._log.info(self.__class__.__name__, 'Metric %s has been created.', metric) alternative.add_metric(metric) self._log.info(self.__class__.__name__, 'Metric %s has been associated to the alternative %s.', metric.get_name(), alternative.get_name())