Uploaded image for project: 'Felix'
  1. Felix
  2. FELIX-5114

Schedule configuration update in Component executor synchronously

    XMLWordPrintableJSON

Details

    Description

      Currently, all external events are handled through the Component queue (Executor). This allows to provide a nice thread model, where no synchronization is required inside DM, and also the user benefits from this because, because all component lifecycle callbacks and all dependency injections are also performed using the internal Component queue. So, in some situation, this model make life easier for the developer.

      But there is an exception to all this: the Configuration Dependency is currently handled from the Configuration Admin dispatcher thread, in other words, a component update callback can be called while a component "bind" method is called from another thread (if a service dependency is injected dynamically from another thread).

      We do this because Configuration Admin requires to throw a ConfigurationException from the update thread, in case there is a configuration error.

      The intent of this issue is simply to stay synchronous (we still throw a ConfigurationException from the CM update thread), but instead of calling the component "updated" callback from the CM thread, we schedule the update callback through the Component internal queue, and we wait for the update callback to be executed (using a simple Callbable associated with a FutureTask.

      This trick will allow to call the component "updated" callback safely, and return any configuration errors to the CM update thread.

      So, basically, instead of doing this in the ConfigurationDependencyImpl.updated callback

              try {
                  invokeUpdated(settings); // either the callback instance or the component instances, if available.
              } catch (ConfigurationException e) {
                  logConfigurationException(e);
                  throw e;
              }
      

      then schedule the update invocation in the component executor and wait for the result like this:

              Callable<ConfigurationException> result = new Callable<ConfigurationException>() {
                  @Override
                  public ConfigurationException call() throws Exception {
                      try {
                          invokeUpdated(settings); // either the callback instance or the component instances, if available.
                      } catch (ConfigurationException e) {
                          return e;
                      }
                      return null;
                  }            
              };
              FutureTask<ConfigurationException> ft = new FutureTask<>(result);
              m_component.getExecutor().execute(ft);
              
              try {
                  ConfigurationException confError = ft.get(UPDATE_MAXWAIT, TimeUnit.MILLISECONDS);
                  if (confError != null) {
                      logConfigurationException(confError);
                      throw confError;
                  }
                }
      
              catch (Throwable error) {
                  logConfigurationException(error);
                  throw new ConfigurationException(null, "Could not handle configuration update", error);
              }
      

      Attachments

        Activity

          People

            pderop Pierre De Rop
            pderop Pierre De Rop
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: