def GenApiConfig(service_class_names, config_string_generator=None, hostname=None, application_path=None): """Write an API configuration for endpoints annotated ProtoRPC services. Args: service_class_names: A list of fully qualified ProtoRPC service classes. config_string_generator: A generator object that produces API config strings using its pretty_print_config_to_json method. hostname: A string hostname which will be used as the default version hostname. If no hostname is specificied in the @endpoints.api decorator, this value is the fallback. application_path: A string with the path to the AppEngine application. Raises: TypeError: If any service classes don't inherit from remote.Service. messages.DefinitionNotFoundError: If a service can't be found. Returns: A map from service names to a string containing the API configuration of the service in JSON format. """ api_service_map = collections.OrderedDict() for service_class_name in service_class_names: module_name, base_service_class_name = service_class_name.rsplit( '.', 1) module = __import__(module_name, fromlist=base_service_class_name) service = getattr(module, base_service_class_name) if not isinstance(service, type) or not issubclass( service, remote.Service): raise TypeError('%s is not a ProtoRPC service' % service_class_name) services = api_service_map.setdefault( (service.api_info.name, service.api_info.version), []) services.append(service) app_yaml_hostname = _GetAppYamlHostname(application_path) service_map = collections.OrderedDict() config_string_generator = (config_string_generator or api_config.ApiConfigGenerator()) for api_info, services in six.iteritems(api_service_map): assert len( services) > 0, 'An API must have at least one ProtoRPC service' hostname = services[ 0].api_info.hostname or hostname or app_yaml_hostname service_map['%s-%s' % api_info] = ( config_string_generator.pretty_print_config_to_json( services, hostname=hostname)) return service_map
def __register_services(api_name_version_map, api_config_registry): """Register & return a list of each SPI URL and class that handles that URL. This finds every service class in api_name_version_map, registers it with the given ApiConfigRegistry, builds the SPI url for that class, and adds the URL and its factory to a list that's returned. Args: api_name_version_map: A mapping from (api name, api version) to a list of service factories, as returned by __create_name_version_map. api_config_registry: The ApiConfigRegistry where service classes will be registered. Returns: A list of (SPI URL, service_factory) for each service class in api_name_version_map. Raises: ApiConfigurationError: If a Service class appears more than once in api_name_version_map. This could happen if one class is used to implement multiple APIs. """ generator = api_config.ApiConfigGenerator() protorpc_services = [] for service_factories in api_name_version_map.itervalues(): service_classes = [ service_factory.service_class for service_factory in service_factories ] config_file = generator.pretty_print_config_to_json( service_classes) api_config_registry.register_spi(config_file) for service_factory in service_factories: protorpc_class_name = service_factory.service_class.__name__ root = _ApiServer.__SPI_PREFIX + protorpc_class_name if any(service_map[0] == root or service_map[1] == service_factory for service_map in protorpc_services): raise api_config.ApiConfigurationError( 'Can\'t reuse the same class in multiple APIs: %s' % protorpc_class_name) protorpc_services.append((root, service_factory)) return protorpc_services