Creating a Blackjack Web Service
Our next example is a web service that assists you in developing a blackjack card game. The Blackjack web service (Fig. 28.13) provides web methods to shuffle a deck of cards, deal a card from the deck and evaluate a hand of cards. After presenting the web service, we use it to serve as the dealer for a game of blackjack (Fig. 28.14). The Blackjack web service uses an HttpSession object to maintain a unique deck of cards for each client ap-plication. Several clients can use the service at the same time, but web method calls made by a specific client use only the deck of cards stored in that client’s session. Our example uses the following blackjack rules:
Two cards each are dealt to the dealer and the player. The player’s cards are dealt face up. Only the first of the dealer’s cards is dealt face up. Each card has a value. A card numbered 2 through 10 is worth its face value. Jacks, queens and kings each count as 10. Aces can count as 1 or 11—whichever value is more beneficial to the player (as we will soon see). If the sum of the player’s two initial cards is 21 (i.e., the player was dealt a card valued at 10 and an ace, which counts as 11 in this situation), the player has “blackjack” and immediately wins the game—if the dealer does not also have blackjack (which would result in a “push”—i.e., a tie). Otherwise, the player can begin taking additional cards one at a time. These cards are dealt face up, and the player decides when to stop taking cards. If the player “busts” (i.e., the sum of the player’s cards exceeds 21), the game is over, and the player loses. When the player is sat-isfied with the current set of cards, the player “stands” (i.e., stops taking cards), and the dealer’s hidden card is revealed. If the dealer’s total is 16 or less, the dealer must take another card; otherwise, the dealer must stand. The dealer must continue taking cards until the sum of the dealer’s cards is greater than or equal to 17. If the dealer exceeds 21, the player wins. Otherwise, the hand with the higher point total wins. If the dealer and the player have the same point total, the game is a “push,” and no one wins. Note that the value of an ace for a dealer depends on the dealer’s other card(s) and the casino’s house rules. A dealer typically must hit for totals of 16 or less and must stand for totals of 17 or more. However, for a “soft 17”—a hand with a total of 17 with one ace counted as 11—some casinos require the dealer to hit and some require the dealer to stand (we require the dealer to stand). Such a hand is known as a “soft 17” because taking another card cannot bust the hand.
The web service (Fig. 28.13) stores each card as a String consisting of a number, 1– 13, representing the card’s face (ace through king, respectively), followed by a space and a digit, 0–3, representing the card’s suit (hearts, diamonds, clubs or spades, respectively). For example, the jack of clubs is represented as "11 2", and the two of hearts is represented as "2 0". To create and deploy this web service, follow the steps presented in Sections 28.3.2–28.3.3 for the HugeInteger service.
154 // Fig. 28.13: Blackjack.java
155 // Blackjack web service that deals cards and evaluates hands
156 package com.deitel.iw3htp4.ch28.blackjack;
203 import java.util.ArrayList;
204 import java.util.Random;
205 import javax.annotation.Resource;
206 import javax.jws.WebService;
207 import javax.jws.WebMethod;
208 import javax.jws.WebParam;
209 import javax.servlet.http.HttpSession;
210 import javax.servlet.http.HttpServletRequest;
211 import javax.xml.ws.WebServiceContext;
212 import javax.xml.ws.handler.MessageContext;
205 @WebService( name = "Blackjack", serviceName = "BlackjackService" )
206 public class Blackjack
208 // use @Resource to create a WebServiceContext for session tracking
209 private @Resource WebServiceContext webServiceContext;
210 private MessageContext messageContext; // used in session tracking
211 private HttpSession session; // stores attributes of the session
1 // deal one card
2 @WebMethod( operationName = "dealCard" )
3 public String dealCard()
5 String card = "";
7 ArrayList< String > deck =
8 ( ArrayList< String > ) session.getAttribute( "deck" );
10 card = deck.get( 0 ); // get top card of deck
11 deck.remove( 0 ); // remove top card of deck
39 return card;
40 } // end WebMethod dealCard
1 // shuffle the deck
2 @WebMethod( operationName = "shuffle" )
3 public void shuffle()
5 // obtain the HttpSession object to store deck for current client
6 messageContext = webServiceContext.getMessageContext();
7 session = ( ( HttpServletRequest ) messageContext.get(
8 MessageContext.SERVLET_REQUEST ) ).getSession();
9 // populate deck of cards
10 ArrayList< String > deck = new ArrayList< String >();
19 for ( int face = 1; face <= 13; face++ ) // loop through faces
20 for ( int suit = 0; suit <= 3; suit++ ) // loop through suits
53 deck.add( face + " " + suit ); // add each card to deck
24 String tempCard; // holds card temporarily during swapping
25 Random randomObject = new Random(); // generates random numbers
26 int index; // index of randomly selected card
31 for ( int i = 0; i < deck.size() ; i++ ) // shuffle
33 index = randomObject.nextInt( deck.size() - 1 );
36 // swap card at position i with randomly selected card
37 tempCard = deck.get( i );
38 deck.set( i, deck.get( index ) );
39 deck.set( index, tempCard );
40 } // end for
41 // add this deck to user's session
42 session.setAttribute( "deck", deck );
43 } // end WebMethod shuffle
46 // determine a hand's value
47 @WebMethod( operationName = "getHandValue" )
48 public int getHandValue( @WebParam( name = "hand" ) String hand )
50 // split hand into cards
51 String cards = hand.split( "\t" );
52 int total = 0; // total value of cards in hand
53 int face; // face of current card
54 int aceCount = 0; // number of aces in hand
53 for ( int i = 0; i < cards.length; i++ )
55 // parse string and get first int in String
face = Integer.parseInt(
87 cards[ i ].substring( 0, cards[ i ].indexOf( " " ) ) );
89 switch ( face )
91 case 1: // if ace, increment aceCount
94 case 11: // jack
95 case 12: // queen
96 case 13: // king
97 total += 10;
99 default: // otherwise, add face
100 total += face;
102 } // end switch
103 } // end for
105 // calculate optimal use of aces
106 if ( aceCount > 0 )
108 // if possible, count one ace as 11
109 if ( total + 11 + aceCount - 1 <= 21 )
110 total += 11 + aceCount - 1;
111 else // otherwise, count all aces as 1
112 total += aceCount;
113 } // end if
115 return total;
116 } // end WebMethod getHandValue
117 } // end class Blackjack
Fig. 28.13 | Blackjack web service that deals cards and evaluates hands.
Session Tracking in Web Services
The Blackjack web service client first calls method shuffle (lines 40–71) to shuffle the deck of cards. This method also places the deck of cards into an HttpSession object that is specific to the client that called shuffle. To use session tracking in a Web service, you must include code for the resources that maintain the session state information. In the past, you had to write the sometimes tedious code to create these resources. JAX-WS, how-ever, handles this for you via the @Resource annotation. This annotation enables tools like Netbeans to “inject” complex support code into your class, thus allowing you to focus on your business logic rather than the support code. The concept of using annotations to add code that supports your classes is known as dependency injection. Annotations like @Web-Service, @WebMethod and @WebParam also perform dependency injection.
Line 20 injects a WebServiceContext object into your class. A WebServiceContext object enables a web service to access and maintain information for a specific request, such as session state. As you look through the code in Fig. 28.13, you’ll notice that we never create the WebServiceContext object. All of the code necessary to create it is injected into the class by the @Resource annotation. Line 21 declares a variable of interface type MessageContext that the web service will use to obtain an HttpSession object for the current client. Line 22 declares the HttpSession variable that the web service will use to manipulate the session state information.
Line 44 in method shuffle uses the WebServiceContext object that was injected in line 20 to obtain a MessageContext object. Lines 45–46 then use the MessageContext object’s get method to obtain the HttpSession object for the current client. Method get receives a constant indicating what to get from the MessageContext. In this case, the constant MessageContext.SERVLET_REQUEST indicates that we’d like to get the HttpServlet-Request object for the current client. We then call method getSession to get the HttpSession object from the HttpServletRequest object.
Lines 49–70 generate an ArrayList representing a deck of cards, shuffle the deck and store the deck in the client’s session object. Lines 51–53 use nested loops to generate Strings in the form "face suit" to represent each possible card in the deck. Lines 59–67 shuffle the deck by swapping each card with another card selected at random. Line 70 inserts the ArrayList in the session object to maintain the deck between method calls from a particular client.
Lines 25–37 define method dealCard as a web method. Lines 30–31 use the session object to obtain the "deck" session attribute that was stored in line 70 of method shuffle. Method getAttribute takes as a parameter a String that identifies the Object to obtain from the session state. The HttpSession can store many Objects, provided that each has a unique identifier. Note that method shuffle must be called before method dealCard is called the first time for a client—otherwise, an exception occurs at line 33 because get-Attribute returns null at lines 30–31. After obtaining the user’s deck, dealCard gets the top card from the deck (line 33), removes it from the deck (line 34) and returns the card’s value as a String (line 36). Without using session tracking, the deck of cards would need to be passed back and forth with each method call. Session tracking makes the dealCard method easy to call (it requires no arguments) and eliminates the overhead of sending the deck over the network multiple times.
Method getHandValue (lines 74–116) determines the total value of the cards in a hand by trying to attain the highest score possible without going over 21. Recall that an ace can be counted as either 1 or 11, and all face cards count as 10. This method does not use the session object because the deck of cards is not used in this method.
As you’ll soon see, the client application maintains a hand of cards as a String in which each card is separated by a tab character. Line 78 tokenizes the hand of cards (rep-resented by hand) into individual cards by calling String method split and passing to it a String containing the delimiter characters (in this case, just a tab). Method split uses the delimiter characters to separate tokens in the String. Lines 83–103 count the value of each card. Lines 86–87 retrieve the first integer—the face—and use that value in the switch statement (lines 89–102). If the card is an ace, the method increments variable aceCount. We discuss how this variable is used shortly. If the card is an 11, 12 or 13 (jack, queen or king), the method adds 10 to the total value of the hand (line 97). If the card is anything else, the method increases the total by that value (line 100).
Because an ace can have either of two values, additional logic is required to process aces. Lines 106–113 of method getHandValue process the aces after all the other cards. If a hand contains several aces, only one ace can be counted as 11. The condition in line 109 determines whether counting one ace as 11 and the rest as 1 will result in a total that does not exceed 21. If this is possible, line 110 adjusts the total accordingly. Otherwise, line 112 adjusts the total, counting each ace as 1.
Method getHandValue maximizes the value of the current cards without exceeding 21. Imagine, for example, that the dealer has a 7 and receives an ace. The new total could be either 8 or 18. However, getHandValue always maximizes the value of the cards without going over 21, so the new total is 18.
Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.