001
/**//* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com */
002
003
package com.db4odoc.semaphores;
004
005
import java.util.*;
006
import com.db4o.*;
007
import com.db4o.config.*;
008
import com.db4o.ext.*;
009
import com.db4o.query.*;
010
011
/** *//**
012
* This class demonstrates how semaphores can be used to rule out race
013
* conditions when providing exact and up-to-date information about
014
* all connected clients on a server. The class also can be used to
015
* make sure that only one login is possible with a give user name and
016
* ipAddress combination.
017
*/
018
public class ConnectedUser ...{
019
020
static final String SEMAPHORE_CONNECTED = "ConnectedUser_";
021
022
static final String SEMAPHORE_LOCK_ACCESS = "ConnectedUser_Lock_";
023
024
static final int TIMEOUT = 10000; // concurrent access timeout
025
026
// 10 seconds
027
028
String userName;
029
030
String ipAddress;
031
032
public ConnectedUser(String userName, String ipAddress) ...{
033
this.userName = userName;
034
this.ipAddress = ipAddress;
035
}
036
037
// make sure to call this on the server before opening the
038
// database
039
// to improve querying speed
040
public static void configure() ...{
041
ObjectClass objectClass = Db4o.configure().objectClass(
042
ConnectedUser.class);
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
048
// record
049
// in the database file and the semaphore set
050
public static void login(ObjectContainer client, String userName,
051
String ipAddress) ...{
052
if (!client.ext()
053
.setSemaphore(SEMAPHORE_LOCK_ACCESS, TIMEOUT)) ...{
054
throw new RuntimeException(
055
"Timeout trying to get access to ConnectedUser lock");
056
}
057
Query q = client.query();
058
q.constrain(ConnectedUser.class);
059
q.descend("userName").constrain(userName);
060
q.descend("ipAddress").constrain(ipAddress);
061
if (q.execute().size() == 0) ...{
062
client.set(new ConnectedUser(userName, ipAddress));
063
client.commit();
064
}
065
String connectedSemaphoreName = SEMAPHORE_CONNECTED
066
+ userName + ipAddress;
067
boolean unique = client.ext().setSemaphore(
068
connectedSemaphoreName, 0);
069
client.ext().releaseSemaphore(SEMAPHORE_LOCK_ACCESS);
070
if (!unique) ...{
071
throw new RuntimeException(
072
"Two clients with same userName and ipAddress");
073
}
074
}
075
076
// here is your list of all connected users, callable on the
077
// server
078
public static List connectedUsers(ObjectServer server) ...{
079
ExtObjectContainer serverObjectContainer = server.ext()
080
.objectContainer().ext();
081
if (serverObjectContainer.setSemaphore(SEMAPHORE_LOCK_ACCESS,
082
TIMEOUT)) ...{
083
throw new RuntimeException(
084
"Timeout trying to get access to ConnectedUser lock");
085
}
086
List list = new ArrayList();
087
Query q = serverObjectContainer.query();
088
q.constrain(ConnectedUser.class);
089
ObjectSet objectSet = q.execute();
090
while (objectSet.hasNext()) ...{
091
ConnectedUser connectedUser = (ConnectedUser) objectSet
092
.next();
093
String connectedSemaphoreName = SEMAPHORE_CONNECTED
094
+ connectedUser.userName
095
+ connectedUser.ipAddress;
096
if (serverObjectContainer.setSemaphore(
097
connectedSemaphoreName, TIMEOUT)) ...{
098
serverObjectContainer.delete(connectedUser);
099
} else ...{
100
list.add(connectedUser);
101
}
102
}
103
serverObjectContainer.commit();
104
serverObjectContainer.releaseSemaphore(SEMAPHORE_LOCK_ACCESS);
105
return list;
106
}
107
}