Controlling Login Information

ConnectedUser.cs
001/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 002using System; 003using System.Collections; 004using Db4objects.Db4o; 005using Db4objects.Db4o.Config; 006using Db4objects.Db4o.Ext; 007using Db4objects.Db4o.Query; 008 009 010namespace Db4objects.Db4odoc.Semaphores 011{ 012 013 /** 014 * This class demonstrates how semaphores can be used 015 * to rule out race conditions when providing exact and 016 * up-to-date information about all connected clients 017 * on a server. The class also can be used to make sure 018 * that only one login is possible with a give user name 019 * and ipAddress combination. 020 */ 021 public class ConnectedUser 022 { 023 024 public readonly static string SEMAPHORE_CONNECTED = "ConnectedUser_"; 025 public readonly static string SEMAPHORE_LOCK_ACCESS = "ConnectedUser_Lock_"; 026 027 public readonly static int TIMEOUT = 10000; // concurrent access timeout 10 seconds 028 029 String userName; 030 String ipAddress; 031 032 public ConnectedUser(String userName, String ipAddress) 033 { 034 this.userName = userName; 035 this.ipAddress = ipAddress; 036 } 037 038 // make sure to call this on the server before opening the database 039 // to improve querying speed 040 public static void Configure() 041 { 042 IObjectClass objectClass = Db4oFactory.Configure().ObjectClass(typeof(ConnectedUser)); 043 objectClass.ObjectField("userName").Indexed(true); 044 objectClass.ObjectField("ipAddress").Indexed(true); 045 } 046 047 // call this on the client to ensure to have a ConnectedUser record 048 // in the database file and the semaphore set 049 public static void Login(IObjectContainer client, String userName, String ipAddress) 050 { 051 if(! client.Ext().SetSemaphore(SEMAPHORE_LOCK_ACCESS, TIMEOUT)) 052 { 053 throw new Exception("Timeout trying to get access to ConnectedUser lock"); 054 } 055 IQuery q = client.Query(); 056 q.Constrain(typeof(ConnectedUser)); 057 q.Descend("userName").Constrain(userName); 058 q.Descend("ipAddress").Constrain(ipAddress); 059 if(q.Execute().Size() == 0) 060 { 061 client.Set(new ConnectedUser(userName, ipAddress)); 062 client.Commit(); 063 } 064 String connectedSemaphoreName = SEMAPHORE_CONNECTED + userName + ipAddress; 065 bool unique = client.Ext().SetSemaphore(connectedSemaphoreName, 0); 066 client.Ext().ReleaseSemaphore(SEMAPHORE_LOCK_ACCESS); 067 if(! unique) 068 { 069 throw new Exception("Two clients with same userName and ipAddress"); 070 } 071 } 072 073 // here is your list of all connected users, callable on the server 074 public static IList ConnectedUsers(IObjectServer server) 075 { 076 IExtObjectContainer serverObjectContainer = server.Ext().ObjectContainer().Ext(); 077 if(serverObjectContainer.SetSemaphore(SEMAPHORE_LOCK_ACCESS, TIMEOUT)) 078 { 079 throw new Exception("Timeout trying to get access to ConnectedUser lock"); 080 } 081 IList list = new ArrayList(); 082 IQuery q = serverObjectContainer.Query(); 083 q.Constrain(typeof(ConnectedUser)); 084 IObjectSet objectSet = q.Execute(); 085 while(objectSet.HasNext()) 086 { 087 ConnectedUser connectedUser = (ConnectedUser)objectSet.Next(); 088 String connectedSemaphoreName = 089 SEMAPHORE_CONNECTED + 090 connectedUser.userName + 091 connectedUser.ipAddress; 092 if(serverObjectContainer.SetSemaphore(connectedSemaphoreName, TIMEOUT)) 093 { 094 serverObjectContainer.Delete(connectedUser); 095 } 096 else 097 { 098 list.Add(connectedUser); 099 } 100 } 101 serverObjectContainer.Commit(); 102 serverObjectContainer.ReleaseSemaphore(SEMAPHORE_LOCK_ACCESS); 103 return list; 104 } 105 } 106}

ConnectedUser.vb
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02Imports System 03Imports System.Collections 04Imports Db4objects.Db4o 05Imports Db4objects.Db4o.Config 06Imports Db4objects.Db4o.Ext 07Imports Db4objects.Db4o.Query 08 09 10Namespace Db4objects.Db4odoc.Semaphores 11 ' 12 ' This class demonstrates how semaphores can be used 13 ' to rule race conditions when providing exact and 14 ' up-to-date information about all connected clients 15 ' on a server. The class also can be used to make sure 16 ' that only one login is possible with a give user name 17 ' and ipAddress combination. 18 ' 19 Public Class ConnectedUser 20 21 Public Shared ReadOnly SEMAPHORE_CONNECTED As String = "ConnectedUser_" 22 Public Shared ReadOnly SEMAPHORE_LOCK_ACCESS As String = "ConnectedUser_Lock_" 23 24 Public Shared ReadOnly TIMEOUT As Integer = 10000 ' concurrent access timeout 10 seconds 25 26 Dim userName As String 27 Dim ipAddress As String 28 29 Public Sub New(ByVal userName As String, ByVal ipAddress As String) 30 Me.userName = userName 31 Me.ipAddress = ipAddress 32 End Sub 33 34 ' make sure to call this on the server before opening the database 35 ' to improve querying speed 36 Public Shared Sub Configure() 37 Dim objectClass As IObjectClass = Db4oFactory.Configure().ObjectClass(GetType(ConnectedUser)) 38 objectClass.ObjectField("userName").Indexed(True) 39 objectClass.ObjectField("ipAddress").Indexed(True) 40 End Sub 41 42 ' call this on the client to ensure to have a ConnectedUser record 43 ' in the database file and the semaphore set 44 Public Shared Sub Login(ByVal client As IObjectContainer, ByVal userName As String, ByVal ipAddress As String) 45 If Not client.Ext().SetSemaphore(SEMAPHORE_LOCK_ACCESS, TIMEOUT) Then 46 Throw New Exception("Timeout Trying to get access to ConnectedUser lock") 47 End If 48 Dim q As IQuery = client.Query() 49 q.Constrain(GetType(ConnectedUser)) 50 q.Descend("userName").Constrain(userName) 51 q.Descend("ipAddress").Constrain(ipAddress) 52 If q.Execute().Size() = 0 Then 53 client.Set(New ConnectedUser(userName, ipAddress)) 54 client.Commit() 55 End If 56 Dim connectedSemaphoreName As String = SEMAPHORE_CONNECTED + userName + ipAddress 57 Dim unique As Boolean = client.Ext().SetSemaphore(connectedSemaphoreName, 0) 58 client.Ext().ReleaseSemaphore(SEMAPHORE_LOCK_ACCESS) 59 If Not unique Then 60 Throw New Exception("Two clients with same userName and ipAddress") 61 End If 62 End Sub 63 64 ' here is your list of all connected users, callable on the server 65 Public Shared Function ConnectedUsers(ByVal server As IObjectServer) As IList 66 Dim serverObjectContainer As IExtObjectContainer = server.Ext().ObjectContainer().Ext() 67 If serverObjectContainer.SetSemaphore(SEMAPHORE_LOCK_ACCESS, TIMEOUT) Then 68 Throw New Exception("Timeout Trying to get access to ConnectedUser lock") 69 End If 70 Dim list As IList = New ArrayList() 71 Dim q As IQuery = serverObjectContainer.Query() 72 q.Constrain(GetType(ConnectedUser)) 73 Dim objectSet As IObjectSet = q.Execute() 74 While objectSet.HasNext() 75 Dim connectedUser As ConnectedUser = CType(objectSet.Next(), ConnectedUser) 76 Dim connectedSemaphoreName As String = SEMAPHORE_CONNECTED + connectedUser.userName + connectedUser.ipAddress 77 If serverObjectContainer.SetSemaphore(connectedSemaphoreName, TIMEOUT) Then 78 serverObjectContainer.Delete(connectedUser) 79 Else 80 list.Add(connectedUser) 81 End If 82 End While 83 serverObjectContainer.Commit() 84 serverObjectContainer.ReleaseSemaphore(SEMAPHORE_LOCK_ACCESS) 85 Return list 86 End Function 87 End Class 88End Namespace