/**
   * Callback when a {@link SettingSpecifierProviderFactory} has been registered.
   *
   * @param provider the provider object
   * @param properties the service properties
   */
  public void onBindFactory(SettingSpecifierProviderFactory provider, Map<String, ?> properties) {
    log.debug("Bind called on factory {} with props {}", provider, properties);
    final String factoryPid = provider.getFactoryUID();

    synchronized (factories) {
      factories.put(factoryPid, new FactoryHelper(provider));

      // find all configured factory instances, and publish those
      // configurations now. First we look up all registered factory
      // instances, so each returned result returns a configured instance
      // key
      List<KeyValuePair> instanceKeys = settingDao.getSettings(getFactorySettingKey(factoryPid));
      for (KeyValuePair instanceKey : instanceKeys) {
        SettingsCommand cmd = new SettingsCommand();
        cmd.setProviderKey(factoryPid);
        cmd.setInstanceKey(instanceKey.getKey());

        // now lookup all settings for the configured instance
        List<KeyValuePair> settings =
            settingDao.getSettings(getFactoryInstanceSettingKey(factoryPid, instanceKey.getKey()));
        for (KeyValuePair setting : settings) {
          SettingValueBean bean = new SettingValueBean();
          bean.setKey(setting.getKey());
          bean.setValue(setting.getValue());
          cmd.getValues().add(bean);
        }
        updateSettings(cmd);
      }
    }
  }
  @SuppressWarnings("unchecked")
  @Override
  public void updateSettings(SettingsCommand command) {
    // group all updates by provider+instance, to reduce the number of CA updates
    // when multiple settings are changed
    if (command.getProviderKey() == null) {
      Map<String, SettingsCommand> groups = new LinkedHashMap<String, SettingsCommand>(8);
      Map<String, SettingsCommand> indexedGroups = null;
      for (SettingValueBean bean : command.getValues()) {
        String groupKey =
            bean.getProviderKey() + (bean.getInstanceKey() == null ? "" : bean.getInstanceKey());
        final boolean indexed = INDEXED_PROP_PATTERN.matcher(bean.getKey()).find();
        SettingsCommand cmd = null;
        if (indexed) {
          // indexed property, add in indexed groups
          if (indexedGroups == null) {
            indexedGroups = new LinkedHashMap<String, SettingsCommand>(8);
          }
          cmd = indexedGroups.get(groupKey);
        } else {
          cmd = groups.get(groupKey);
        }

        if (cmd == null) {
          cmd = new SettingsCommand();
          cmd.setProviderKey(bean.getProviderKey());
          cmd.setInstanceKey(bean.getInstanceKey());
          if (indexed) {
            indexedGroups.put(groupKey, cmd);
          } else {
            groups.put(groupKey, cmd);
          }
        }
        cmd.getValues().add(bean);
      }
      for (SettingsCommand cmd : groups.values()) {
        updateSettings(cmd);
      }
      if (indexedGroups != null) {
        for (SettingsCommand cmd : indexedGroups.values()) {
          updateSettings(cmd);
        }
      }
      return;
    }

    try {
      Configuration conf = getConfiguration(command.getProviderKey(), command.getInstanceKey());
      Dictionary<String, Object> props = conf.getProperties();
      if (props == null) {
        props = new Hashtable<String, Object>();
      }
      for (SettingValueBean bean : command.getValues()) {
        String settingKey = command.getProviderKey();
        String instanceKey = command.getInstanceKey();
        if (instanceKey != null) {
          settingKey = getFactoryInstanceSettingKey(settingKey, instanceKey);
        }
        if (bean.isRemove()) {
          props.remove(bean.getKey());
        } else {
          props.put(bean.getKey(), bean.getValue());
        }

        if (!bean.isTransient()) {
          if (bean.isRemove()) {
            settingDao.deleteSetting(settingKey, bean.getKey());
          } else {
            settingDao.storeSetting(settingKey, bean.getKey(), bean.getValue());
          }
        }
      }
      if (conf != null && props != null) {
        if (command.getInstanceKey() != null) {
          props.put(OSGI_PROPERTY_KEY_FACTORY_INSTANCE_KEY, command.getInstanceKey());
        }
        conf.update(props);
      }

    } catch (IOException e) {
      throw new RuntimeException(e);
    } catch (InvalidSyntaxException e) {
      throw new RuntimeException(e);
    }
  }