You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2004/05/01 09:14:07 UTC

svn commit: rev 10477 - in incubator/directory/rms/trunk/je/src: java/org/apache/rms/je/profile test/org/apache/rms/je/profile

Author: akarasulu
Date: Sat May  1 00:14:06 2004
New Revision: 10477

Modified:
   incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeLinkUserNameKeyCreator.java
   incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileRoleLinkDAO.java
   incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileUserNameKeyCreator.java
   incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitor.java
   incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitorAdapter.java
   incubator/directory/rms/trunk/je/src/test/org/apache/rms/je/profile/JeProfileRoleLinkDAOTest.java
Log:
Commit changes ...

 o completed listUserNames() and listRoleNames() methods on role link DAO 
 o completed and passed unit tests for these list methods
 o added monitor interfaces for these methods 
 o implemented no-op monitor methods for these interfaces

To do list ...

 o review monitor methods cuz they're really messed up
 o make role link dao implement the observer pattern which tracks dangling
   cursors within iterators that have not been closed. 



Modified: incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeLinkUserNameKeyCreator.java
==============================================================================
--- incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeLinkUserNameKeyCreator.java	(original)
+++ incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeLinkUserNameKeyCreator.java	Sat May  1 00:14:06 2004
@@ -26,7 +26,7 @@
 
 
 /**
- * A userName key creator for the Profile database's secondary database.
+ * A roleName key creator for the Profile database's secondary database.
  * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
@@ -39,7 +39,7 @@
 
 
     /**
-     * Sets the profile userName bytes for the result entry by extracting it
+     * Sets the profile roleName bytes for the result entry by extracting it
      * from the dataEntry.
      *
      * @param secondaryDatabase the secondary database the new key is for

Modified: incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileRoleLinkDAO.java
==============================================================================
--- incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileRoleLinkDAO.java	(original)
+++ incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileRoleLinkDAO.java	Sat May  1 00:14:06 2004
@@ -19,11 +19,12 @@
 
 import org.apache.rms.je.JeUtils ;
 import org.apache.rms.je.JeRmsException;
+import org.apache.rms.je.JeIterator;
 import org.apache.rms.RmsException ;
 import org.apache.rms.je.sequence.Sequence ;
 
-import org.apache.commons.lang.NotImplementedException ;
 import org.apache.commons.lang.Validate ;
+import org.apache.commons.lang.NotImplementedException;
 
 import java.util.List ;
 import java.util.Iterator ;
@@ -47,7 +48,7 @@
             new JeProfileRoleLinkBinding() ;
     /** the name of secondary db used to associate links with an appName */
     public static final String APPNAME_SECDB  = "roleLinkByAppName" ;
-    /** the name of secondary db used to associate links with an userName */
+    /** the name of secondary db used to associate links with an roleName */
     public static final String USERNAME_SECDB = "roleLinkByUserName" ;
     /** the name of secondary db used to associate links with an roleName */
     public static final String ROLENAME_SECDB = "roleLinkByRoleName" ;
@@ -59,7 +60,7 @@
 
     /** the secondary database for looking up links by appName */
     private SecondaryDatabase byAppName ;
-    /** the secondary database for looking up links by userName */
+    /** the secondary database for looking up links by roleName */
     private SecondaryDatabase byUserName ;
     /** the secondary database for looking up links by roleName */
     private SecondaryDatabase byRoleName ;
@@ -437,7 +438,7 @@
     public Iterator listRoleNames( String appName, String userName )
             throws RmsException
     {
-        throw new NotImplementedException( "STUB" ) ;
+        return new RoleLinkRoleNameIterator( appName, userName ) ;
     }
 
 
@@ -455,7 +456,7 @@
     public Iterator listUserNames( String appName, String roleName )
             throws RmsException
     {
-        throw new NotImplementedException( "STUB" ) ;
+        return new RoleLinkUserNameIterator( appName, roleName ) ;
     }
 
 
@@ -468,7 +469,14 @@
      */
     public void close( Iterator list )
     {
-        throw new NotImplementedException( "STUB" ) ;
+        if ( list instanceof RoleLinkRoleNameIterator )
+        {
+            ( ( RoleLinkRoleNameIterator ) list ).close() ;
+        }
+        else if ( list instanceof RoleLinkUserNameIterator )
+        {
+            ( ( RoleLinkUserNameIterator ) list ).close() ;
+        }
     }
 
 
@@ -590,7 +598,6 @@
     {
         if ( cursor == null )
         {
-            monitor.cleanedUp( this, "close", cursor ) ;
             return ;
         }
 
@@ -602,6 +609,8 @@
         {
             monitor.failedOnCleanupOperation( this, "close", cursor, e ) ;
         }
+
+        monitor.cleanedUp( this, "close", cursor ) ;
     }
 
 
@@ -614,7 +623,6 @@
     {
         if ( cursor == null )
         {
-            monitor.cleanedUp( this, "close", cursor ) ;
             return ;
         }
 
@@ -626,6 +634,8 @@
         {
             monitor.failedOnCleanupOperation( this, "close", cursor, e ) ;
         }
+
+        monitor.cleanedUp( this, "close", cursor ) ;
     }
 
 
@@ -657,8 +667,288 @@
 
 
     // -----------------------------------------------------------------------
-    // Cursor Iterator
+    // Cursor Based Iterators
     // -----------------------------------------------------------------------
 
 
+    /**
+     * An iterator over the set of role names a user application profile
+     * is associated with.
+     */
+    class RoleLinkRoleNameIterator extends JeIterator
+    {
+        final DatabaseEntry key = new DatabaseEntry() ;
+        final DatabaseEntry value = new DatabaseEntry() ;
+        final DatabaseEntry appNameKey = new DatabaseEntry() ;
+        final DatabaseEntry userNameKey = new DatabaseEntry() ;
+
+        final String appName ;
+        final String userName ;
+
+        JoinCursor cursor = null ;
+        SecondaryCursor appNameCursor = null ;
+        SecondaryCursor userNameCursor = null ;
+
+
+        /**
+         * An iterator over the set of role names a user application profile
+         * is associated with.
+         *
+         * @param appName the name of the application
+         * @param userName the name of the user
+         * @throws RmsException if there is a failure while accessing the
+         * backing store to setup this iterator
+         */
+        RoleLinkRoleNameIterator( String appName, String userName )
+                throws RmsException
+        {
+            this.appName = appName ;
+            this.userName = userName ;
+
+            // ---------------------------------------------------------------
+            // set the keys for both user and app name cursors
+            // ---------------------------------------------------------------
+
+            try
+            {
+                appNameKey.setData( appName.getBytes( "UTF-8" ) ) ;
+                userNameKey.setData( userName.getBytes( "UTF-8" ) ) ;
+            }
+            catch ( UnsupportedEncodingException e )
+            {
+                monitor.failedLinkBinding( JeProfileRoleLinkDAO.this,
+                        "RoleLinkRoleNameIterator(<init>)", appName, userName,
+                        "unknown", e ) ;
+                throw new RmsException( e ) ;
+            }
+
+            try
+            {
+                // ---------------------------------------------------------------
+                // setup the application name cursor
+                // ---------------------------------------------------------------
+
+                appNameCursor = byAppName.openSecondaryCursor( null, null ) ;
+                setStatus( appNameCursor.getSearchKey( appNameKey, value, LockMode.DEFAULT ) ) ;
+                if ( getStatus() != OperationStatus.SUCCESS )
+                {
+                    monitor.initFailure( JeProfileRoleLinkDAO.this, this,
+                            appName, userName ) ;
+                    throw new JeRmsException( getStatus(), "application " + appName
+                        + " lookup in secondary failed with status " + getStatus() )  ;
+                }
+
+                // ---------------------------------------------------------------
+                // setup the user name cursor
+                // ---------------------------------------------------------------
+
+                userNameCursor = byUserName.openSecondaryCursor( null, null ) ;
+                setStatus( userNameCursor.getSearchKey( userNameKey, value,
+                        LockMode.DEFAULT ) ) ;
+                if ( getStatus() != OperationStatus.SUCCESS )
+                {
+                    monitor.initFailure( JeProfileRoleLinkDAO.this, this,
+                            appName, userName ) ;
+                    throw new JeRmsException( getStatus(), "user " + userName
+                        + " lookup in secondary failed with status " + getStatus() )  ;
+                }
+
+                // ---------------------------------------------------------------
+                // prepare the cursor array and the join cursor
+                // ---------------------------------------------------------------
+
+                SecondaryCursor [] secCursors = {
+                    appNameCursor, userNameCursor
+                } ;
+                cursor = db.join( secCursors, null ) ;
+                setStatus( cursor.getNext( key, value, LockMode.DEFAULT ) ) ;
+            }
+            catch ( DatabaseException e )
+            {
+                close() ;
+                monitor.roleIteratorSetupFailure( this, appName, userName, e ) ;
+                throw new RmsException( e ) ;
+            }
+
+
+            if ( getStatus() == OperationStatus.SUCCESS )
+            {
+                try
+                {
+                    setPrefetched( BINDING.getRoleName( value ) ) ;
+                    getMonitor().prefetch( this, getPrefetched() ) ;
+                }
+                catch ( IOException e )
+                {
+                    close( e ) ;
+                    getMonitor().prefetchFailure( this ) ;
+                    throw new RmsException( e ) ;
+                }
+
+                getMonitor().prefetch( this, getPrefetched() ) ;
+            }
+            else
+            {
+                close() ;
+                monitor.roleIteratorEmpty( JeProfileRoleLinkDAO.this, this,
+                        appName, userName ) ;
+            }
+        }
+
+
+        protected void cleanup() throws Exception
+        {
+            closeNoError( cursor ) ;
+            closeNoError( appNameCursor ) ;
+            closeNoError( userNameCursor ) ;
+        }
+
+
+        protected Object prefetch() throws Exception
+        {
+            setStatus( cursor.getNext( key, value, LockMode.DEFAULT ) ) ;
+            return BINDING.getRoleName( value ) ;
+        }
+    }
+
+
+    /**
+     * An iterator over the set of user names an application role is
+     * associated with.
+     */
+    class RoleLinkUserNameIterator extends JeIterator
+    {
+        final DatabaseEntry key = new DatabaseEntry() ;
+        final DatabaseEntry value = new DatabaseEntry() ;
+        final DatabaseEntry appNameKey = new DatabaseEntry() ;
+        final DatabaseEntry roleNameKey = new DatabaseEntry() ;
+
+        final String appName ;
+        final String roleName ;
+
+        JoinCursor cursor = null ;
+        SecondaryCursor appNameCursor = null ;
+        SecondaryCursor roleNameCursor = null ;
+
+
+        /**
+         * An iterator over the set of user names an application profile is
+         * associated with.
+         *
+         * @param appName the name of the application
+         * @param roleName the name of the user
+         * @throws RmsException if there is a failure while accessing the
+         * backing store to setup this iterator
+         */
+        RoleLinkUserNameIterator( String appName, String roleName )
+                throws RmsException
+        {
+            this.appName = appName ;
+            this.roleName = roleName ;
+
+            // ---------------------------------------------------------------
+            // set the keys for both user and app name cursors
+            // ---------------------------------------------------------------
+
+            try
+            {
+                appNameKey.setData( appName.getBytes( "UTF-8" ) ) ;
+                roleNameKey.setData( roleName.getBytes( "UTF-8" ) ) ;
+            }
+            catch ( UnsupportedEncodingException e )
+            {
+                monitor.failedLinkBinding( JeProfileRoleLinkDAO.this,
+                        "RoleLinkUserNameIterator(<init>)", appName, roleName,
+                        "unknown", e ) ;
+                throw new RmsException( e ) ;
+            }
+
+            try
+            {
+                // ---------------------------------------------------------------
+                // setup the application name cursor
+                // ---------------------------------------------------------------
+
+                appNameCursor = byAppName.openSecondaryCursor( null, null ) ;
+                setStatus( appNameCursor.getSearchKey( appNameKey, value, LockMode.DEFAULT ) ) ;
+                if ( getStatus() != OperationStatus.SUCCESS )
+                {
+                    monitor.initFailure( JeProfileRoleLinkDAO.this, this,
+                            appName, roleName ) ;
+                    throw new JeRmsException( getStatus(), "application " + appName
+                        + " lookup in secondary failed with status " + getStatus() )  ;
+                }
+
+                // ---------------------------------------------------------------
+                // setup the role name cursor
+                // ---------------------------------------------------------------
+
+                roleNameCursor = byRoleName.openSecondaryCursor( null, null ) ;
+                setStatus( roleNameCursor.getSearchKey( roleNameKey, value,
+                        LockMode.DEFAULT ) ) ;
+                if ( getStatus() != OperationStatus.SUCCESS )
+                {
+                    monitor.initFailure( JeProfileRoleLinkDAO.this, this,
+                            appName, roleName ) ;
+                    throw new JeRmsException( getStatus(), "role " + roleName
+                        + " lookup in secondary failed with status " + getStatus() )  ;
+                }
+
+                // ---------------------------------------------------------------
+                // prepare the cursor array and the join cursor
+                // ---------------------------------------------------------------
+
+                SecondaryCursor [] secCursors = {
+                    appNameCursor, roleNameCursor
+                } ;
+                cursor = db.join( secCursors, null ) ;
+                setStatus( cursor.getNext( key, value, LockMode.DEFAULT ) ) ;
+            }
+            catch ( DatabaseException e )
+            {
+                close() ;
+                monitor.roleIteratorSetupFailure( this, appName, roleName, e ) ;
+                throw new RmsException( e ) ;
+            }
+
+
+            if ( getStatus() == OperationStatus.SUCCESS )
+            {
+                try
+                {
+                    setPrefetched( BINDING.getUserName( value ) ) ;
+                    getMonitor().prefetch( this, getPrefetched() ) ;
+                }
+                catch ( IOException e )
+                {
+                    close( e ) ;
+                    getMonitor().prefetchFailure( this ) ;
+                    throw new RmsException( e ) ;
+                }
+
+                getMonitor().prefetch( this, getPrefetched() ) ;
+            }
+            else
+            {
+                close() ;
+                monitor.roleIteratorEmpty( JeProfileRoleLinkDAO.this, this,
+                        appName, roleName ) ;
+            }
+        }
+
+
+        protected void cleanup() throws Exception
+        {
+            closeNoError( cursor ) ;
+            closeNoError( appNameCursor ) ;
+            closeNoError( roleNameCursor ) ;
+        }
+
+
+        protected Object prefetch() throws Exception
+        {
+            setStatus( cursor.getNext( key, value, LockMode.DEFAULT ) ) ;
+            return BINDING.getUserName( value ) ;
+        }
+    }
 }

Modified: incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileUserNameKeyCreator.java
==============================================================================
--- incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileUserNameKeyCreator.java	(original)
+++ incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/JeProfileUserNameKeyCreator.java	Sat May  1 00:14:06 2004
@@ -26,7 +26,7 @@
 
 
 /**
- * A userName key creator for the Profile database's secondary database.
+ * A roleName key creator for the Profile database's secondary database.
  * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
@@ -38,7 +38,7 @@
 
 
     /**
-     * Sets the profile userName bytes for the result entry by extracting it
+     * Sets the profile roleName bytes for the result entry by extracting it
      * from the dataEntry.
      *
      * @param secondaryDatabase the secondary database the new key is for

Modified: incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitor.java
==============================================================================
--- incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitor.java	(original)
+++ incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitor.java	Sat May  1 00:14:06 2004
@@ -19,6 +19,8 @@
 
 import com.sleepycat.je.DatabaseException;
 
+import java.util.Iterator;
+
 
 /**
  * A monitor interface for the Profile to Role link data access object.
@@ -196,4 +198,35 @@
      */
     void roleLinkDeleted( ProfileRoleLinkDAO dao, String appName,
                           String userName, String roleName ) ;
-}
+
+    void initFailure( ProfileRoleLinkDAO dao, Iterator list, String appName,
+                      String userName ) ;
+
+
+    void roleIteratorEmpty( JeProfileRoleLinkDAO jeProfileRoleLinkDAO,
+                            JeProfileRoleLinkDAO.RoleLinkRoleNameIterator roleLinkRoleNameIterator, String appName,
+                            String userName );
+
+
+    void roleIteratorSetupFailure( JeProfileRoleLinkDAO.RoleLinkRoleNameIterator roleLinkRoleNameIterator,
+                                   String appName, String userName, DatabaseException e );
+
+
+    void roleIteratorSetupFailure( JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkUserNameIterator,
+                                   String appName, String roleName );
+
+
+    void roleIteratorReady( JeProfileRoleLinkDAO jeProfileRoleLinkDAO,
+                            JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkUserNameIterator, String appName,
+                            String roleName, String prefetched );
+
+
+    void roleIteratorEmpty( JeProfileRoleLinkDAO jeProfileRoleLinkDAO,
+                            JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkRoleNameIterator, String appName,
+                            String roleName );
+
+
+    void roleIteratorSetupFailure( JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkRoleNameIterator,
+                                   String appName, String roleName, DatabaseException e );
+
+}
\ No newline at end of file

Modified: incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitorAdapter.java
==============================================================================
--- incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitorAdapter.java	(original)
+++ incubator/directory/rms/trunk/je/src/java/org/apache/rms/je/profile/ProfileRoleLinkDAOMonitorAdapter.java	Sat May  1 00:14:06 2004
@@ -17,6 +17,11 @@
 package org.apache.rms.je.profile ;
 
 
+import com.sleepycat.je.DatabaseException;
+
+import java.util.Iterator;
+
+
 /**
  * A no-op monitor adapter for the Profile to Role link data access object.
  * At a bare minimum this adapter dumps faulting exceptions to stderr.
@@ -138,6 +143,74 @@
 
     public void roleLinkDeleted( ProfileRoleLinkDAO dao, String appName,
                                  String userName, String roleName )
+    {
+    }
+
+
+    /////////////////////////////////////////////////////////////////////////
+
+    //                           Crap from here on                         //
+
+
+    public void roleIteratorFailure( JeProfileRoleLinkDAO.RoleLinkRoleNameIterator roleLinkRoleNameIterator,
+                                     String appName, String userName, DatabaseException e )
+    {
+    }
+
+
+    public void roleIteratorReady( JeProfileRoleLinkDAO jeProfileRoleLinkDAO,
+                                   JeProfileRoleLinkDAO.RoleLinkRoleNameIterator roleLinkRoleNameIterator,
+                                   String appName, String userName, String prefetched )
+    {
+    }
+
+
+    public void roleIteratorSetupFailure( JeProfileRoleLinkDAO.RoleLinkRoleNameIterator roleLinkRoleNameIterator,
+                                          String appName, String userName, DatabaseException e )
+    {
+    }
+
+
+    public void roleIteratorEmpty( JeProfileRoleLinkDAO jeProfileRoleLinkDAO,
+                                   JeProfileRoleLinkDAO.RoleLinkRoleNameIterator roleLinkRoleNameIterator,
+                                   String appName, String userName )
+    {
+    }
+
+
+    public void roleIteratorSetupFailure( JeProfileRoleLinkDAO.RoleLinkRoleNameIterator roleLinkRoleNameIterator,
+                                          String appName, String userName )
+    {
+    }
+
+
+    public void roleIteratorSetupFailure( JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkRoleNameIterator,
+                                          String appName, String roleName )
+    {
+    }
+
+
+    public void roleIteratorSetupFailure( JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkRoleNameIterator,
+                                          String appName, String roleName, DatabaseException e )
+    {
+    }
+
+
+    public void roleIteratorReady( JeProfileRoleLinkDAO jeProfileRoleLinkDAO,
+                                   JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkRoleNameIterator,
+                                   String appName, String roleName, String prefetched )
+    {
+    }
+
+
+    public void roleIteratorEmpty( JeProfileRoleLinkDAO jeProfileRoleLinkDAO,
+                                   JeProfileRoleLinkDAO.RoleLinkUserNameIterator roleLinkRoleNameIterator,
+                                   String appName, String roleName )
+    {
+    }
+
+
+    public void initFailure( ProfileRoleLinkDAO dao, Iterator list, String appName, String userName )
     {
     }
 }

Modified: incubator/directory/rms/trunk/je/src/test/org/apache/rms/je/profile/JeProfileRoleLinkDAOTest.java
==============================================================================
--- incubator/directory/rms/trunk/je/src/test/org/apache/rms/je/profile/JeProfileRoleLinkDAOTest.java	(original)
+++ incubator/directory/rms/trunk/je/src/test/org/apache/rms/je/profile/JeProfileRoleLinkDAOTest.java	Sat May  1 00:14:06 2004
@@ -24,6 +24,8 @@
 import com.sleepycat.je.SecondaryConfig;
 import com.sleepycat.je.Database;
 
+import java.util.Iterator;
+
 
 /**
  * A unit test case for a Je based Profile to role link data access object.
@@ -149,5 +151,41 @@
         assertFalse( dao.has( "app2", "user1", "roleB" ) ) ;
         assertFalse( dao.has( "app2", "user2", "roleB" ) ) ;
         assertFalse( dao.has( "app2", "roleA" ) ) ;
+    }
+
+
+    public void testListUserAndRoleNames() throws Exception
+    {
+        assertFalse( dao.has( "app1", "user1", "roleA" ) ) ;
+        assertFalse( dao.has( "app1", "user2", "roleA" ) ) ;
+        assertFalse( dao.has( "app1", "roleA" ) ) ;
+
+        assertFalse( dao.has( "app2", "user1", "roleB" ) ) ;
+        assertFalse( dao.has( "app2", "user2", "roleB" ) ) ;
+        assertFalse( dao.has( "app2", "roleA" ) ) ;
+
+        dao.create( "app1", "user1", "roleA" ) ;
+        dao.create( "app1", "user2", "roleA" ) ;
+        dao.create( "app2", "user1", "roleB" ) ;
+        dao.create( "app2", "user2", "roleB" ) ;
+
+        assertTrue( dao.has( "app1", "user1", "roleA" ) ) ;
+        assertTrue( dao.has( "app1", "user2", "roleA" ) ) ;
+        assertTrue( dao.has( "app1", "roleA" ) ) ;
+        assertFalse( dao.has( "app1", "roleB" ) ) ;
+
+        assertTrue( dao.has( "app2", "user1", "roleB" ) ) ;
+        assertTrue( dao.has( "app2", "user2", "roleB" ) ) ;
+        assertTrue( dao.has( "app2", "roleB" ) ) ;
+        assertFalse( dao.has( "app2", "roleA" ) ) ;
+
+        Iterator list = dao.listUserNames( "app1", "roleA" ) ;
+        assertEquals( "user1", list.next() ) ;
+        assertEquals( "user2", list.next() ) ;
+        assertFalse( list.hasNext() ) ;
+
+        list = dao.listRoleNames( "app2", "user1" ) ;
+        assertEquals( "roleB", list.next() ) ;
+        assertFalse( list.hasNext() ) ;
     }
 }