Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Applied Java™ Patterns - Stephen Stelting, Olav Maassen.pdf
Скачиваний:
202
Добавлен:
24.05.2014
Размер:
2.84 Mб
Скачать

Session identification – A server must be able to maintain the client’s identity over the lifetime of the application.

Session representation – Depending on the needs of the application, one or more session objects might be used to represent state.

Benefits and Drawbacks

The central benefits of the Session pattern are evident from its characteristics: identifying service requesters and maintaining state-based resources. Secondary advantages might exist, as well, depending on the model chosen for implementing the pattern. For instance, if client identity is established as a result of a login, the Session can manage accountability and prioritization when accessing server-side resources. If Session information is stored in a database, the server can maintain information about a client’s state over a series of business transactions.

A drawback of the Session is its increased workload on the server, and the increased complexity required of server software. Beyond its normal requirements, a Session-based server must have some way to establish client identity, store and retrieve associated information, and validate client identity on a number of occasions during the application.

Pattern Variants

The principal variations of the Session center around the key issues of identity and state.

Managing session identity – You can use three approaches:

Security-based identification – A login provides a session ID for the client.

Implicit identification – A long-term connection between client and server automatically validates identity.

Arbitrary identification – The server assigns a unique session ID to each client. The ID is arbitrary and is used only to track a client during a single use of the server.

Managing session state – In Sessions where state is required, you can maintain information in the following ways, on the client or the server:

Object-based storage, client side – The client takes responsibility for data storage and sends what is required to the server. This reduces overall application security; data is present on a client, potentially a less secure machine. However, it is easy to associate the data with a client, since the client stores the information and sends it to the server. Another benefit of this approach is that it reduces the load on the server, requiring a client application to store its own data.

How this is implemented varies depending on your technology; in HTTP, this approach is implemented using cookies.

Object-based storage, server side – The server stores any data for its clients, and uses what is required during client requests. The server maintains all the application data, so there is a heavier load on the server. However, overall system security tends to be higher since data is maintained on the server. System efficiency is usually higher as well, since there is no redundant transfer of data. The challenge that you might face with server-side storage lies in establishing client identity, since the client and its data are decoupled in the application.

In HTTP and Java, this approach means using HttpSession.

Related Patterns

None.

Example

Note:

For a full working example of this code example, with additional supporting classes and/or a RunPattern class, see “ Session ” on page 507 of the “ Full Code Examples ” appendix.

150

A Session component diagram for a client-matching session is shown in Figure 4.2.

Figure 4.2. Session component for a client-matching session

A second Session component diagram, this time for server-maintained sessions, is shown in Figure 4.3.

Figure 4.3. Session component for server-maintained sessions

A Session tracker diagram is shown in

Figure 4.4.

 

Y

 

 

L

 

 

F

Figure 4.4. Session tracker

 

 

M

 

A

E

 

T

 

 

In this example, the client requester uses the server to perform a series of operations for updating contact information in a shared address book. A user can perform four operations:

Add a contact

Add an address (associated with the current contact)

Remove an address (associated with the current contact)

Save the contact and address changes

These operations are defined in the class SessionClient.

Example 4.6 SessionClient.java

1.import java.net.MalformedURLException;TEAM FLY PRESENTS

2.import java.rmi.Naming;

151

3.import java.rmi.NotBoundException;

4.import java.rmi.RemoteException;

5.public class SessionClient{

6.private static final String SESSION_SERVER_SERVICE_NAME = "sessionServer";

7.private static final String SESSION_SERVER_MACHINE_NAME = "localhost";

8.private long sessionID;

9.private SessionServer sessionServer;

10.

11.public SessionClient(){

12.try{

13. String url = "//" + SESSION_SERVER_MACHINE_NAME + "/" + SESSION_SERVER_SERVICE_NAME; 14. sessionServer = (SessionServer)Naming.lookup(url);

15.}

16.catch (RemoteException exc){}

17.catch (NotBoundException exc){}

18.catch (MalformedURLException exc){}

19.catch (ClassCastException exc){}

20.}

21.

22.public void addContact(Contact contact) throws SessionException{

23.try{

24. sessionID = sessionServer.addContact(contact, 0);

25.}

26.catch (RemoteException exc){}

27.}

28.

29.public void addAddress(Address address) throws SessionException{

30.try{

31. sessionServer.addAddress(address, sessionID);

32.}

33.catch (RemoteException exc){}

34.}

35.

36.public void removeAddress(Address address) throws SessionException{

37.try{

38. sessionServer.removeAddress(address, sessionID);

39.}

40.catch (RemoteException exc){}

41.}

42.

43.public void commitChanges() throws SessionException{

44.try{

45. sessionID = sessionServer.finalizeContact(sessionID);

46.}

47.catch (RemoteException exc){}

48.}

49.}

Each client method calls a corresponding method on the remote server. SessionServer defines the four methods available to the clients through RMI.

Example 4.7 SessionServer.java

1.import java.rmi.Remote;

2.import java.rmi.RemoteException;

3.public interface SessionServer extends Remote{

4.public long addContact(Contact contact, long sessionID) throws RemoteException,

SessionException;

5.public long addAddress(Address address, long sessionID) throws RemoteException,

SessionException;

6.public long removeAddress(Address address, long sessionID) throws RemoteException,

SessionException;

7.public long finalizeContact(long sessionID) throws RemoteException, SessionException;

8.}

SessionServerImpl implements the SessionServer interface, providing an RMI server. It delegates business

behavior to the class SessionServerDelegate.

Example 4.8 SessionServerImpl.java

1.import java.rmi.Naming;

2.import java.rmi.server.UnicastRemoteObject;

3.public class SessionServerImpl implements SessionServer{

4.private static final String SESSION_SERVER_SERVICE_NAME = "sessionServer";

5.public SessionServerImpl(){

6.try {

7. UnicastRemoteObject.exportObject(this);

152

8. Naming.rebind(SESSION_SERVER_SERVICE_NAME, this);

9.}

10.catch (Exception exc){

11.System.err.println("Error using RMI to register the SessionServerImpl " + exc);

12.}

13.}

14.

15.public long addContact(Contact contact, long sessionID) throws SessionException{

16.return SessionServerDelegate.addContact(contact, sessionID);

17.}

18.

19.public long addAddress(Address address, long sessionID) throws SessionException{

20.return SessionServerDelegate.addAddress(address, sessionID);

21.}

22.

23.public long removeAddress(Address address, long sessionID) throws SessionException{

24.return SessionServerDelegate.removeAddress(address, sessionID);

25.}

26.

27.public long finalizeContact(long sessionID) throws SessionException{

28.return SessionServerDelegate.finalizeContact(sessionID);

29.}

30.}

Example 4.9 SessionServerDelegate.java

1.import java.util.ArrayList;

2.import java.util.HashMap;

3.public class SessionServerDelegate{

4.private static final long NO_SESSION_ID = 0;

5.private static long nextSessionID = 1;

6.private static ArrayList contacts = new ArrayList();

7.private static ArrayList addresses = new ArrayList();

8.private static HashMap editContacts = new HashMap();

10.public static long addContact(Contact contact, long sessionID) throws SessionException{

11.if (sessionID <= NO_SESSION_ID){

12. sessionID = getSessionID();

13.}

14.if (contacts.indexOf(contact) != -1){

15.

if (!editContacts.containsValue(contact)){

16.

editContacts.put(new Long(sessionID), contact);

17.

}

18.

else{

19.

throw new SessionException("This contact is currently being edited by another

20.

user.",

SessionException.CONTACT_BEING_EDITED);

21.

}

22.}

23.else{

24.

contacts.add(contact);

25.

editContacts.put(new Long(sessionID), contact);

26.}

27.return sessionID;

28.}

29.

30.public static long addAddress(Address address, long sessionID) throws SessionException{

31.if (sessionID <= NO_SESSION_ID){

32.throw new SessionException("A valid session ID is required to add an address",

33. SessionException.SESSION_ID_REQUIRED);

34.}

35.Contact contact = (Contact)editContacts.get(new Long(sessionID));

36.if (contact == null){

37.throw new SessionException("You must select a contact before adding an address",

38. SessionException.CONTACT_SELECT_REQUIRED);

39.}

40.if (addresses.indexOf(address) == -1){

41. addresses.add(address);

42.}

43.contact.addAddress(address);

44.return sessionID;

45.}

46.

47.public static long removeAddress(Address address, long sessionID) throws SessionException{

48.if (sessionID <= NO_SESSION_ID){

49.throw new SessionException("A valid session ID is required to remove an address",

50. SessionException.SESSION_ID_REQUIRED);

51.}

153

52.Contact contact = (Contact)editContacts.get(new Long(sessionID));

53.if (contact == null){

54.throw new SessionException("You must select a contact before removing an address",

55. SessionException.CONTACT_SELECT_REQUIRED);

56.}

57.if (addresses.indexOf(address) == -1){

58. throw new SessionException("There is no record of this address", 59. SessionException.ADDRESS_DOES_NOT_EXIST);

60.}

61.contact.removeAddress(address);

62.return sessionID;

63.}

64.

65.public static long finalizeContact(long sessionID) throws SessionException{

66.if (sessionID <= NO_SESSION_ID){

67. throw new SessionException("A valid session ID is required to finalize a contact", 68. SessionException.SESSION_ID_REQUIRED);

69.}

70.Contact contact = (Contact)editContacts.get(new Long(sessionID));

71.if (contact == null){

72.throw new SessionException("You must select and edit a contact before committing

changes",

73. SessionException.CONTACT_SELECT_REQUIRED);

74.}

75.editContacts.remove(new Long(sessionID));

76.return NO_SESSION_ID;

77.}

78.

79.private static long getSessionID(){

80.return nextSessionID++;

81.}

82.

83.public static ArrayList getContacts(){ return contacts; }

84.public static ArrayList getAddresses(){ return addresses; }

85.public static ArrayList getEditContacts(){ return new ArrayList( editContacts.values()); }

86.}

SessionServerDelegate generates a session ID for clients when they perform their first operation, adding a Contact. Subsequent operations on the Contact's addresses require the session ID, since the ID is used to associate the addresses with a specific Contact within the SessionServerDelegate.

154