01
/**//* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */
02
03
package com.db4odoc.f1.semaphores;
04
05
06
import java.util.*;
07
import com.db4o.*;
08
import com.db4o.config.*;
09
import com.db4o.ext.*;
10
import com.db4o.query.*;
11
12
/** *//**
13
* This class demonstrates how semaphores can be used
14
* to rule out race conditions when providing exact and
15
* up-to-date information about all connected clients
16
* on a server. The class also can be used to make sure
17
* that only one login is possible with a give user name
18
* and ipAddress combination.
19
*/
20
public class ConnectedUser ...{
21
22
static final String SEMAPHORE_CONNECTED = "ConnectedUser_";
23
static final String SEMAPHORE_LOCK_ACCESS = "ConnectedUser_Lock_";
24
25
static final int TIMEOUT = 10000; // concurrent access timeout 10 seconds
26
27
String userName;
28
String ipAddress;
29
30
public ConnectedUser(String userName, String ipAddress)...{
31
this.userName = userName;
32
this.ipAddress = ipAddress;
33
}
34
35
// make sure to call this on the server before opening the database
36
// to improve querying speed
37
public static void configure()...{
38
ObjectClass objectClass = Db4o.configure().objectClass(ConnectedUser.class);
39
objectClass.objectField("userName").indexed(true);
40
objectClass.objectField("ipAddress").indexed(true);
41
}
42
43
// call this on the client to ensure to have a ConnectedUser record
44
// in the database file and the semaphore set
45
public static void login(ObjectContainer client, String userName, String ipAddress)...{
46
if(! client.ext().setSemaphore(SEMAPHORE_LOCK_ACCESS, TIMEOUT))...{
47
throw new RuntimeException("Timeout trying to get access to ConnectedUser lock");
48
}
49
Query q = client.query();
50
q.constrain(ConnectedUser.class);
51
q.descend("userName").constrain(userName);
52
q.descend("ipAddress").constrain(ipAddress);
53
if(q.execute().size() == 0)...{
54
client.set(new ConnectedUser(userName, ipAddress));
55
client.commit();
56
}
57
String connectedSemaphoreName = SEMAPHORE_CONNECTED + userName + ipAddress;
58
boolean unique = client.ext().setSemaphore(connectedSemaphoreName, 0);
59
client.ext().releaseSemaphore(SEMAPHORE_LOCK_ACCESS);
60
if(! unique)...{
61
throw new RuntimeException("Two clients with same userName and ipAddress");
62
}
63
}
64
65
// here is your list of all connected users, callable on the server
66
public static List connectedUsers(ObjectServer server)...{
67
ExtObjectContainer serverObjectContainer = server.ext().objectContainer().ext();
68
if(serverObjectContainer.setSemaphore(SEMAPHORE_LOCK_ACCESS, TIMEOUT))...{
69
throw new RuntimeException("Timeout trying to get access to ConnectedUser lock");
70
}
71
List list = new ArrayList();
72
Query q = serverObjectContainer.query();
73
q.constrain(ConnectedUser.class);
74
ObjectSet objectSet = q.execute();
75
while(objectSet.hasNext())...{
76
ConnectedUser connectedUser = (ConnectedUser)objectSet.next();
77
String connectedSemaphoreName =
78
SEMAPHORE_CONNECTED +
79
connectedUser.userName +
80
connectedUser.ipAddress;
81
if(serverObjectContainer.setSemaphore(connectedSemaphoreName, TIMEOUT))...{
82
serverObjectContainer.delete(connectedUser);
83
}else...{
84
list.add(connectedUser);
85
}
86
}
87
serverObjectContainer.commit();
88
serverObjectContainer.releaseSemaphore(SEMAPHORE_LOCK_ACCESS);
89
return list;
90
}
91
}