text: #!/usr/bin/env python
  #
  # Copyright (c) 2016 Cisco and/or its affiliates.
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at:
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import os
  
  import callback_gen
  import util
  from string import Template
  
  notification_registry_template = Template("""
  package $plugin_package.$notification_package;
  
  /**
   * <p>Registry for notification callbacks defined in ${plugin_name}.
   * <br>It was generated by notification_gen.py based on $inputfile
   * <br>(python representation of api file generated by vppapigen).
   */
  public interface ${plugin_name}EventRegistry extends $base_package.$notification_package.EventRegistry {
  
      $register_callback_methods
  
      @Override
      void close();
  }
  """)
  
  global_notification_callback_template = Template("""
  package $plugin_package.$notification_package;
  
  /**
   * <p>Aggregated callback interface for notifications only.
   * <br>It was generated by notification_gen.py based on $inputfile
   * <br>(python representation of api file generated by vppapigen).
   */
  public interface Global${plugin_name}EventCallback$callbacks {
  
  }
  """)
  
  notification_registry_impl_template = Template("""
  package $plugin_package.$notification_package;
  
  /**
   * <p>Notification registry delegating notification processing to registered callbacks.
   * <br>It was generated by notification_gen.py based on $inputfile
   * <br>(python representation of api file generated by vppapigen).
   */
  public final class ${plugin_name}EventRegistryImpl implements ${plugin_name}EventRegistry, Global${plugin_name}EventCallback {
  
      // TODO add a special NotificationCallback interface and only allow those to be registered
      private final java.util.concurrent.ConcurrentMap<Class<?>, $base_package.$callback_package.JVppCallback> registeredCallbacks =
          new java.util.concurrent.ConcurrentHashMap<>();
      private static java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(${plugin_name}EventRegistryImpl.class.getName());
  
      $register_callback_methods
      $handler_methods
  
      @Override
      public void close() {
          registeredCallbacks.clear();
      }
  
      @Override
      public void onError(io.fd.vpp.jvpp.VppCallbackException ex) {
          java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(${plugin_name}EventRegistryImpl.class.getName());
          LOG.log(java.util.logging.Level.WARNING, String.format("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(),
              ex.getCtxId(), ex.getErrorCode()), ex);
      }
  }
  """)
  
  register_callback_impl_template = Template("""
      public java.lang.AutoCloseable register$callback(final $plugin_package.$callback_package.$callback callback){
          if(null != registeredCallbacks.putIfAbsent($plugin_package.$dto_package.$notification.class, callback)){
              throw new IllegalArgumentException("Callback for " + $plugin_package.$dto_package.$notification.class +
                  "notification already registered");
          }
          return () -> registeredCallbacks.remove($plugin_package.$dto_package.$notification.class);
      }
  """)
  
  handler_impl_template = Template("""
      @Override
      public void on$notification(
          final $plugin_package.$dto_package.$notification_reply notification) {
          if (LOG.isLoggable(java.util.logging.Level.FINE)) {
              LOG.fine(String.format("Received $notification event message: %s", notification));
          }
          final $base_package.$callback_package.JVppCallback jVppCallback = registeredCallbacks.get($plugin_package.$dto_package.$notification.class);
          if (null != jVppCallback) {
              (($plugin_package.$callback_package.$callback) registeredCallbacks
                  .get($plugin_package.$dto_package.$notification.class))
                  .on$notification(notification);
          }
      }
  """)
  
  notification_provider_template = Template("""
  package $plugin_package.$notification_package;
  
   /**
   * Provides ${plugin_name}EventRegistry.
   * <br>The file was generated by notification_gen.py based on $inputfile
   * <br>(python representation of api file generated by vppapigen).
   */
  public interface ${plugin_name}EventRegistryProvider extends $base_package.$notification_package.EventRegistryProvider {
  
      @Override
      public ${plugin_name}EventRegistry getEventRegistry();
  }
  """)
  
  
  def generate_notification_registry(func_list, base_package, plugin_package, plugin_name, notification_package, callback_package, dto_package, inputfile):
      """ Generates notification registry interface and implementation """
      print "Generating Notification interfaces and implementation"
  
      if not os.path.exists(notification_package):
          os.mkdir(notification_package)
  
      callbacks = []
      register_callback_methods = []
      register_callback_methods_impl = []
      handler_methods = []
      for func in func_list:
  
          if not util.is_reply(func['name']) and not util.is_notification(func['name']):
              continue
  
          camel_case_name_with_suffix = util.underscore_to_camelcase_upper(func['name'])
          if util.is_control_ping(camel_case_name_with_suffix):
              continue
          notification_dto = camel_case_name_with_suffix
          callback_ifc = camel_case_name_with_suffix + callback_gen.callback_suffix
          fully_qualified_callback_ifc = "{0}.{1}.{2}".format(plugin_package, callback_package, callback_ifc)
          callbacks.append(fully_qualified_callback_ifc)
  
          # TODO create NotificationListenerRegistration and return that instead of AutoCloseable to better indicate
          # that the registration should be closed
          register_callback_methods.append("java.lang.AutoCloseable register{0}({1} callback);"
                                           .format(callback_ifc, fully_qualified_callback_ifc))
          register_callback_methods_impl.append(register_callback_impl_template.substitute(plugin_package=plugin_package,
                                                                                           callback_package=callback_package,
                                                                                           dto_package=dto_package,
                                                                                           notification=camel_case_name_with_suffix,
                                                                                           callback=callback_ifc))
          handler_methods.append(handler_impl_template.substitute(base_package=base_package,
                                                                  plugin_package=plugin_package,
                                                                  callback_package=callback_package,
                                                                  dto_package=dto_package,
                                                                  notification=notification_dto,
                                                                  notification_reply=camel_case_name_with_suffix,
                                                                  callback=callback_ifc))
  
  
      callback_file = open(os.path.join(notification_package, "%sEventRegistry.java" % plugin_name), 'w')
      callback_file.write(notification_registry_template.substitute(inputfile=inputfile,
                                                                  register_callback_methods="\n    ".join(register_callback_methods),
                                                                  base_package=base_package,
                                                                  plugin_package=plugin_package,
                                                                  plugin_name=plugin_name,
                                                                  notification_package=notification_package))
      callback_file.flush()
      callback_file.close()
  
      callback_file = open(os.path.join(notification_package, "Global%sEventCallback.java" % plugin_name), 'w')
  
      global_notification_callback_callbacks = ""
      if (callbacks):
          global_notification_callback_callbacks = " extends " + ", ".join(callbacks)
  
      callback_file.write(global_notification_callback_template.substitute(inputfile=inputfile,
                                                                         callbacks=global_notification_callback_callbacks,
                                                                         plugin_package=plugin_package,
                                                                         plugin_name=plugin_name,
                                                                         notification_package=notification_package))
      callback_file.flush()
      callback_file.close()
  
      callback_file = open(os.path.join(notification_package, "%sEventRegistryImpl.java" % plugin_name), 'w')
      callback_file.write(notification_registry_impl_template.substitute(inputfile=inputfile,
                                                                       callback_package=callback_package,
                                                                       dto_package=dto_package,
                                                                       register_callback_methods="".join(register_callback_methods_impl),
                                                                       handler_methods="".join(handler_methods),
                                                                       base_package=base_package,
                                                                       plugin_package=plugin_package,
                                                                       plugin_name=plugin_name,
                                                                       notification_package=notification_package))
      callback_file.flush()
      callback_file.close()
  
      callback_file = open(os.path.join(notification_package, "%sEventRegistryProvider.java" % plugin_name), 'w')
      callback_file.write(notification_provider_template.substitute(inputfile=inputfile,
                                                                       base_package=base_package,
                                                                       plugin_package=plugin_package,
                                                                       plugin_name=plugin_name,
                                                                       notification_package=notification_package))
      callback_file.flush()
      callback_file.close()
  
  