/**
   * Returns a collection with all roles matching a given key-value pair.
   *
   * @param key the key to search for;
   * @param value the value to search for.
   * @return a list with all matching roles, can be empty, but never <code>null</code>.
   */
  public List getRoles(String key, String value) {
    if (key == null) {
      throw new IllegalArgumentException("Key cannot be null!");
    }
    if (value == null) {
      throw new IllegalArgumentException("Value cannot be null!");
    }

    List matchingRoles = new ArrayList();

    try {
      String criteria = "(".concat(key).concat("=").concat(value).concat(")");

      Role[] roles = m_store.getRoles(criteria);
      for (int i = 0; i < roles.length; i++) {
        Role role = roles[i];
        if (!isPredefinedRole(role.getName())) {
          matchingRoles.add(wireChangeListener(role));
        }
      }
    } catch (Exception e) {
      throw new BackendException("Failed to get roles!", e);
    }

    return matchingRoles;
  }
  /** @see UserAdminUtil#fireEvent(int, Role) */
  @Override
  public void fireEvent(int type, Role role) {
    if (null == role) {
      throw new IllegalArgumentException("parameter role must not be null");
    }
    ServiceReference<?> reference = userAdminRegistration.getReference();
    final UserAdminEvent uaEvent = new UserAdminEvent(reference, type, role);
    //
    // send event to all listeners, asynchronously - in a separate thread!!
    //
    UserAdminListener[] eventListeners = listenerService.getServices(new UserAdminListener[0]);
    if (null != eventListeners) {
      for (Object listenerObject : eventListeners) {
        final UserAdminListener listener = (UserAdminListener) listenerObject;
        eventExecutor.execute(
            new Runnable() {

              @Override
              public void run() {
                listener.roleChanged(uaEvent);
              }
            });
      }
    }
    //
    // send event to EventAdmin if present
    //
    EventAdmin eventAdmin = m_eventService.getService();
    String name = getEventTypeName(type);
    if (null != eventAdmin && name != null) {
      Dictionary<String, Object> properties = new Hashtable<String, Object>();
      properties.put("event", uaEvent);
      properties.put("role", role);
      properties.put("role.name", role.getName());
      properties.put("role.type", role.getType());
      properties.put("service", reference);
      properties.put("service.id", reference.getProperty(Constants.SERVICE_ID));
      properties.put("service.objectClass", reference.getProperty(Constants.OBJECTCLASS));
      properties.put("service.pid", reference.getProperty(Constants.SERVICE_PID));
      //
      Event event = new Event(PaxUserAdminConstants.EVENT_TOPIC_PREFIX + name, properties);
      eventAdmin.postEvent(event);
    } else {
      String message =
          "No event service available or incompatible type - cannot send event of type '"
              + name
              + "' for role '"
              + role.getName()
              + "'";
      logMessage(this, LogService.LOG_DEBUG, message);
    }
  }
  /**
   * Returns a collection with all roles matching a given filter.
   *
   * @param filter the filter to match the individual roles against, can be <code>null</code> if all
   *     roles should be returned.
   * @return a list with all matching roles, can be empty, but never <code>null</code>.
   */
  public List getRoles(String filter) {
    List matchingRoles = new ArrayList();

    try {
      Role[] roles = m_store.getRoles(sanitizeFilter(filter));
      for (int i = 0; i < roles.length; i++) {
        Role role = roles[i];
        if (!isPredefinedRole(role.getName())) {
          matchingRoles.add(wireChangeListener(role));
        }
      }
    } catch (Exception e) {
      throw new BackendException("Failed to get roles!", e);
    }

    return matchingRoles;
  }