Enterprise JavaBeans, Third Edition by Richard Monson-Haefel Unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. This page was updated February 25, 2004. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification UNCONFIRMED errors and suggestions from readers: {3} 2; ffd [114] Deploying the TravelAgent EJB; Creating two different jar files: one for the CabinEJB and another one for the TravelAgentEJB is very weird. With this packaging, the Orion server (Oracle) cannot run the application client Client_3. I had to struggle to find out why I could not run the Client_3 application. (131) Bottom of page; I believe that the method signature for the last line on the page should have a return type of CustomerRemote. I believe that the line should be as follows: public CustomerRemote findByPrimaryKey(Integer id) throws FinderException, RemoteException; instead of public Customer findByPrimaryKey(Integer id) throws FinderException, RemoteException; (144) Last example at bottom of page; I believe that the import statement should be as follows: import javax.ejb.RemoveException; instead of import javax.ejb.RemoteException; [166] Client code example and related text; In the standalone client application on pg 166 (and thruout the book) the client is looking up "CustomerHomeRemote" without explaining where this name comes from! The deployment descriptors (e.g. page 164) define the name "CustomerEJB" via the tag, but nowhere is the string "CustomerHomeRemote" defined explicitly. Since JBuilder 7 / Borland Enterprise Server defines this remote home name via a Borland- specific XML file, it begs the question as to what the standard requires and in general where the lookup name comes from. If this name is specified by yet another vendor defined mechanism then the book should clarify this point. Or, if there is a standard,(such as "use the classname minus the package name" as pages 164-166 imply) then the book should spell that out. {166} Client Application source code; In the body of the first for loop, args[i] is used both to create the primary key, the firstName AND the lastName of the customer. Not sure how useful and/or practical this would be, even for the demonstration purposes. {178} first code fragment; the exception EJBException which is declared in the throws clause of method setAddress is a RuntimeException and would not have to be declared. {190} code segment; first line of the code: public class CustomerBean inplements javax.ejb.EntityBean{ should be public abstract class CustomerBean implements javax.ejb.EntityBean{ it lost the "abstract" modifier. [199-200] Last line of code; The book code says iterator.remove(phone). As someone else mentioned the Iterator.remove() method takes no arguments. However, the code I downloaded changed that line to phoneNumbers.remove(phone), i.e. it removes the phone number directly from the Collection using the Collection.remove(Object) method. The problem is that on the top of page 201 it wanrns specifically not to use the Collection.add() and Collection.remove() methods while an iterator is in use, and says to only use the Iterator.remove() method. This corresponds with the Sun Javadocs, which state in the Iterator.remove() method explanation: "The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method." So, I guess the code in the book on page 199 should be iterator.remove() and the downloadable code is wrong since it calls the Collection's remove() method. (201) end of first paragraph; You write "... calling the methods Collection.add and Collection.remove while an iterator is in use will result in a IllegalStateException". Actually, calling the add and remove methods will not throw the IllegalStateException, but when an Iterator is used after these calls, the iterator throws the IllegalStateException. {215} first full paragraph; "...the RESERVATION_CUSTOMER_LINK table... should be "...the CUSTOMER_RESERVATION_LINK table..." (267) First paragraph under 'The Remote Home Interface' section; The sentence: In our home interface, we provide only a single create method. should be changed to: In our home interface, we provide two create methods. (since there are two create methods defined in the ShipHomeRemote interface below that sentence!) (282) 2nd paragraph; Remove the word "is" from the sentence that starts "The is exception should always be thrown..." {282} 2ns sentence in 4th paragraph; The remote interface returned by the findByPrimaryKey() method is ShipRemote, not Ship. {287} First code sample; The findByPrimaryKey() method should return ShipRemote, not Ship. [292] first code sample; ShipBean should implement javax.ejb.EntityBean, not extend it. [303] Code sample bottom of page; Shouldn't: public class A_Bean extends EntityBean instead be: public class A_Bean implements EntityBean? {308} second paragraph; "the EntityContext.getPrimary() method..." should be "the EntityContext.getPrimaryKey() method..." {324} where the byCredit() method throws a new PaymentException; The line that reads: throw new PaymentException("Expiration date has"+ " passed"); should probably just be: throw new PaymentException("Expiration date has passed"); There doesn't appear to be any need to concatenate the two strings. Perhaps there used to be a variable in there that was removed? {341} Code where TicketDO object is created; The code that parses the price should be: double price = Double.valueOf(...).doubleValue(); instead of double price = double.valueOf(...).doubleValue(); The valueOf() method is a static method of java.lang.Double. {352} 7th line in code snippet; There are two semicolons ending the line that reads: PreparedStatement ps = null;; (353) Second sentence of the last paragraph; Change "an" to "a" in the second sentence of the last paragraph, which currently reads: "We could have opted to return an collection of remote Cabin references, but we didn't." (353-354) Last sentence on page 353 (continues on to page 354); The last sentence on page 353 (which continues on page 354) appears to be missing the word "references" after the word remote: "In addition, using a collection of remote [references] would requre the client to work with many stubs, each with its own connection to EJB objects on the server." {361} first line; javax.jta.UserTransaction does not exist!!! It should be javax.transaction.UserTransaction see - http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/transaction/UserTransaction.html (366) last paragraph; "It's good programming practice to close a TopicConnection after its been used..." should read "It's good programming practice to close a TopicConnection after it has been used..." -or, less preferentially -- "It's good programming practice to close a TopicConnection after it's been used..." The word "its" should be replaced with the contraction intended, hence "it's" or "it has". (367) Middle of page (first bold line); Change MapMessage mapMsg = session.createTextMessage( ); To MapMessage mapMsg = session.createMapMessage( ); (369) 5th line from bottom (in code sample); System.out.println("\n RESERVATION RECIEVED:\n"+text); RECIEVED is spelled incorrectly; should be RECEIVED. (376) Code sample; factory.createQueueConnection() is spelled wrong. It is spelled as createQueueConnecition(). {379} Variable declaration for Context in ReservationProcessorBean class; Need the following import statements in ReservationProcessorBean: import javax.naming.Context; import javax.naming.InitialContext; {385} 2nd paragraph; QueueConnection connect = factory.createQueueConneciton should read QueueConnection connect = factory.createQueueConnection {388} code sample, 2nd line of code; Minor typo - missing the "t" in the setStringProperty(...) method call [392] Queue for ticket should be created, after reservation queue and then should be setJMSReplyTo(queue) in the at beginning of the cycle; You can see mistake in sample chapter on this site there is no way to be sent reply to the Ticket's queue because it is getJMSReplyTo in DeliverTicket but not setJMSReplyTo in Producer client. I looked at the woorkbook and there it was correct! (416) Middle of the page, phantom read scenario; I think the last sentence of text in both scenario numbers 2 and 4 are incorrect. Number 2 should read that Cabin 99 is NOT in the list of available cabins, and number 4 should read that Cabin 99 is NOW in the list of available cabins. This is required to be consistent with the definition of a phantom read and with the explanation of the scenario given right under it (the record does not show up the first time listAvailableCabins is called but it does show up the second time). {419} I noticed an error in the 3rd edition of "Enterprise JavaBeans", by Richard Monson-Haefel. In Chapter 14, "Transactions", on page 419, the last sentence of the second paragraph in section "Balancing Performance Against Consistency" reads The Serializable isolation level ensures that data is never accessed concurrently by transactions, thus ensuring that the data is always consistent. Actually, the meaning of "Serializable" is that the result obtained would be as though the data were never accessed concurrently, even if in fact concurrent access occurs. Where there is no conflict, such as the case when all access is simply to read the database, then concurrent access is allowed. For example, if 50 processes read the same column from the same row, and no updates occurred, then all 50 processes could read as concurrently as the underlying hardware would allow, and Serializable access would be achieved. See p. 40 of Java Enterprise In a Nutshell, which describes TRANSACTION_SERIALIZABLE as follows: ..this level of isolation forces the database to treat transactions as if they occurred one at a time. (emphasis added.) Put another way, Serializable isolation can be obtained if read locks prevent write locks, and write locks are serialized. Your description could be called "Serialized" access. It's one way to implement Serializable, but it's overkill. (422, 423) Bottom of page 422, bottom of page 423; On the bottom of page 422 the code example shows obtaining a UserTransaction with the following code: UserTransaction tran = (UserTransaction)jndiCntx.lookup("java:comp/UserTransaction"); I think this should be: UserTransaction tran = (UserTransaction)jndiCntx.lookup("java:comp/env/UserTransaction"); Which would be consistent with the same code then displayed on the bottom of page 423. {423} HypotheticalBean code example; HypotheticalBean should implement the SessionBean interface, not extend it. {425-428} EJBs definitions: code source of the catch statement ; for each BMT EJBs definition : it would be clearer to have the rollback statement in the catch statement: so }catch(Exception e){ throw new EJBexception(e); } becomes: }catch(Exception e){ ejbContext.getUserTransaction().rollback(); throw new EJBexception(e); } for the BMT examples, it should be the bean developer to decide to rollback the transaction and not the client. (427-428) MDB: definition of the BMT; ejbContext.getUserTransaction().begin(); in bold ejbContext.getUserTransaction.commit(); : it lacks the brackets. [429] code at bottom of page; The book states that javax.transaction.UserTransaction.begin() throws IllegalStateException but the API states that that it throws NotSupportedException. This error is carried throught the next several pages. [451,457] source example; the 2 data classes (CabinData & CruiseSheduleItem) should be tagged Serializable (implements java.io.Serializable), due to the fact the data will be transfered via RMI {457-8} 3 examples of Schedule remote interface; Schedule remote interface should extend javax.ejb.EJBObject, not implement it. {462} HypotheticalBean example; HypotheticalBean should implement the EntityBean interface, not extend it. [463] Code following 4th paragraph; public interface ShipRemote extends ShipBusiness, javax.ejb.EJBObject should be: public interface ShipRemote implements ShipBusiness, javax.ejb.EJBObject (470-471) EJB 2.0 deployment descriptor; The deployment descriptor uses the primary key class CabinPK which has not been used elsewhere in the book. It then also lists the element (top of page 471) which is an element not used if there is a composite key declared. The deployment descriptor should either have java.lang.Integer (to be consistent with all of the other CabinEJB examples in the book) or, if using the CabinPK class as the primary key, omit the element. (476) Definition of ejb-name element; should be (479) last paragraphh on page; In the 4th sentence from the bottom, listing the elements required for the message driven beans, the element listed does not exist in the DTD. It should read . (484) 5th and 6th paragraph under the "Remote references" heading; The tag in the first and second paragraph under "Remote references" is not a valid tag name. The tag should be read as . {486} Java code sample; The variable 'CabinHome' should probably be 'CabinHomeLocal' since the code is illustrating local interface not remote {495} Deployment descriptor code sample; The elements all should be elements, as there is no element [528] Sequence diagram. insert data into database; According to this database insert occur after ejbPostCreate. But if you read EJB specs from sun(ejb2_1_prd_specs.pdf) page 185 last 2 lines on this page it says database inser occur after ejbCreate method is complete. Primary Key is available in ejbPostCreate method by using ejbPostCreate(...){ ... System.out.println("Primary key iin post create method is :"+ this.entityContext.getEJBObject().getPrimaryKey()); ... } The output on server console is : Post Create called Primary key in post create method is :1245 ejb store called So db insert take place after ejbCreate rather then ejbPostCreate. Please correct me if I am wrong on it. {530} Figures; In the Figure B-4, the arrow for business method from EJB OBJ to Contianer should be corrected from EJB Obj to "Bean Instance". {531} Figure; In Figure B-5 Data Sync Part, ejbStore() should occures after business method. So, READ before business method, and then Save it to DB again.