/** Constructs a SecurityAuditManager, setting up the provider, and a listener. */
  private SecurityAuditManager() {
    // Load an security audit provider.
    initProvider();

    // Detect when a new security audit provider class is set
    PropertyEventListener propListener =
        new PropertyEventListener() {
          @Override
          public void propertySet(String property, Map params) {
            if ("provider.securityAudit.className".equals(property)) {
              initProvider();
            }
          }

          @Override
          public void propertyDeleted(String property, Map params) {
            // Ignore
          }

          @Override
          public void xmlPropertySet(String property, Map params) {
            // Ignore
          }

          @Override
          public void xmlPropertyDeleted(String property, Map params) {
            // Ignore
          }
        };
    PropertyEventDispatcher.addListener(propListener);
  }
  public void start() throws IllegalStateException {
    super.start();
    if (isEnabled()) {
      // Before starting up service make sure there is a default secret
      if (ExternalComponentManager.getDefaultSecret() == null
          || "".equals(ExternalComponentManager.getDefaultSecret())) {
        try {
          ExternalComponentManager.setDefaultSecret(StringUtils.randomString(10));
        } catch (ModificationNotAllowedException e) {
          Log.warn("Failed to set a default secret to external component service", e);
        }
      }
      // Make sure that external component service is enabled
      if (!ExternalComponentManager.isServiceEnabled()) {
        try {
          ExternalComponentManager.setServiceEnabled(true);
        } catch (ModificationNotAllowedException e) {
          Log.warn("Failed to start external component service", e);
        }
      }
      // Listen for changes to external component settings
      ExternalComponentManager.addListener(this);
      // Listen for registration of new components
      InternalComponentManager.getInstance().addListener(this);
      // Listen for changes in certificates
      CertificateManager.addListener(this);
      // Listen for property changes
      PropertyEventDispatcher.addListener(this);
      // Set up custom clearspace MUC service
      // Create service if it doesn't exist, load if it does.
      MultiUserChatServiceImpl muc =
          (MultiUserChatServiceImpl)
              XMPPServer.getInstance()
                  .getMultiUserChatManager()
                  .getMultiUserChatService(MUC_SUBDOMAIN);
      if (muc == null) {
        try {
          muc =
              XMPPServer.getInstance()
                  .getMultiUserChatManager()
                  .createMultiUserChatService(MUC_SUBDOMAIN, MUC_DESCRIPTION, true);
        } catch (AlreadyExistsException e) {
          Log.error(
              "ClearspaceManager: Found no "
                  + MUC_SUBDOMAIN
                  + " service, but got already exists when creation attempted?  Service probably not started!");
        }
      }
      if (muc != null) {
        // Set up special delegate for Clearspace MUC service
        muc.setMUCDelegate(new ClearspaceMUCEventDelegate());
        // Set up additional features for Clearspace MUC service
        muc.addExtraFeature("clearspace:service");
        // Set up additional identity of conference service to Clearspace MUC service
        muc.addExtraIdentity("conference", "Clearspace Chat Service", "text");
      }

      // Starts the clearspace configuration task
      startClearspaceConfig();

      // Starts the Clearspace MUC transcript manager
      mucTranscriptManager.start();
    }
  }