class MappedAuthProvider implements AuthProvider
{
    /**
     * Name of the property of which the value is expected to be the classname of the AuthProviderMapper instance to be
     * used by instances of this class.
     */
    public static final String PROPERTY_MAPPER_CLASSNAME = "mappedAuthProvider.mapper.className";

    /**
     * Used to determine what provider is to be used to operate on a particular user.
     */
    protected final AuthProviderMapper mapper;

    public MappedAuthProvider()
    {
        // Migrate properties.
        JiveGlobals.migrateProperty( PROPERTY_MAPPER_CLASSNAME );

        // Instantiate mapper.
        final String mapperClass = JiveGlobals.getProperty( PROPERTY_MAPPER_CLASSNAME );
        if ( mapperClass == null )
        {
            throw new IllegalStateException( "A mapper must be specified via openfire.xml or the system properties." );
        }

        try
        {
            final Class c = ClassUtils.forName( mapperClass );
            mapper = (AuthProviderMapper) c.newInstance();
        }
        catch ( Exception e )
        {
            throw new IllegalStateException( "Unable to create new instance of AuthProviderMapper class: " + mapperClass, e );
        }
    }

    @Override
    public void authenticate( String username, String password ) throws UnauthorizedException, ConnectionException, InternalUnauthenticatedException
    {
        final AuthProvider provider = mapper.getAuthProvider( username );
        if ( provider == null )
        {
            throw new UnauthorizedException();
        }
        provider.authenticate( username, password );
    }

    @Override
    public String getPassword( String username ) throws UserNotFoundException, UnsupportedOperationException
    {
        final AuthProvider provider = mapper.getAuthProvider( username );
        if ( provider == null )
        {
            throw new UserNotFoundException();
        }
        return provider.getPassword( username );
    }

    @Override
    public void setPassword( String username, String password ) throws UserNotFoundException, UnsupportedOperationException
    {
        final AuthProvider provider = mapper.getAuthProvider( username );
        if ( provider == null )
        {
            throw new UserNotFoundException();
        }
        provider.setPassword( username, password );
    }

    @Override
    public boolean supportsPasswordRetrieval()
    {
        // TODO Make calls concurrent for improved throughput.
        for ( final AuthProvider provider : mapper.getAuthProviders() )
        {
            // If at least one provider supports password retrieval, so does this proxy.
            if ( provider.supportsPasswordRetrieval() )
            {
                return true;
            }
        }

        return false;
    }

    @Override
    public boolean isScramSupported()
    {<FILL_FUNCTION_BODY>}

    @Override
    public String getSalt(String username) throws UserNotFoundException
    {
        final AuthProvider provider = mapper.getAuthProvider( username );
        if ( provider == null )
        {
            throw new UserNotFoundException();
        }
        return provider.getSalt( username );
    }

    @Override
    public int getIterations(String username) throws UserNotFoundException
    {
        final AuthProvider provider = mapper.getAuthProvider( username );
        if ( provider == null )
        {
            throw new UserNotFoundException();
        }
        return provider.getIterations( username );
    }

    @Override
    public String getServerKey(String username) throws UserNotFoundException
    {
        final AuthProvider provider = mapper.getAuthProvider( username );
        if ( provider == null )
        {
            throw new UserNotFoundException();
        }
        return provider.getServerKey( username );
    }

    @Override
    public String getStoredKey(String username) throws UserNotFoundException
    {
        final AuthProvider provider = mapper.getAuthProvider( username );
        if ( provider == null )
        {
            throw new UserNotFoundException();
        }
        return provider.getStoredKey( username );
    }
}

        // TODO Make calls concurrent for improved throughput.
        for ( final AuthProvider provider : mapper.getAuthProviders() )
        {
            // If at least one provider supports SCRAM, so does this proxy.
            if ( provider.isScramSupported() )
            {
                return true;
            }
        }

        return false;
    
<no_super_class>