However, it may be that the physical schema of the persistent data store especially ifthat persistent data store is an RDBMS does not correspond exactly with the logicalschema of the Ent
Trang 1and the entityelement defined as
<!ELEMENT entity (description?, display-name?, small-icon?, large-icon?, ejb-name, home?, remote?, local-home?, local?, ejb-class,
persistence-type, prim-key-class, reentrant, cmp-version?, abstract-schema-name?, cmp-field*, primkey-field?,
env-entry*, ejb-ref*, ejb-local-ref*, security-role-ref*, security-identity?, resource-ref*,
resource-env-ref*, query*)>
Looking first at theentityelement, much of it will be unchanged What needs to bespecified for a CMP entity are
• cmp-version Always set to 2.0 The value 1.1is supported only for legacy CMPEntity beans written to the EJB 1.1 specification
• abstract-schema-name Any unique name, this defines the name used to identifythe bean in EJB QL queries It makes sense to base this on the name of the bean
In the case study, the JobBeanbean has a schema with the name of Job
• cmp-field One for each cmp-field(but not cmr-fields) In the Jobbean, thecmp-fields are ref, customer, and description The locationand skillsfieldsare cmr-fields representing relations to the Locationand Skillbeans respective-
ly, and so do not appear
• primkey-field This optional field is used when the primkey-classelementdoes not identify a custom primary key class It is not specified for the Jobbean,but for the Locationbean, for example, it is specified and is set to name
• query Defines an EJB QL query, associating it with a finder or select method.Listing 7.12 shows the entityelement for the Jobbean
LISTING 7.12 Job Bean’s entity Element
Trang 231: <! shouldn’t be needed, but
➥ctx.getEJBHome() returns null in J2EE RI >
53: WHERE j.customer = ?1</ejb-ql>
54: </query>
Trang 365: WHERE o.location.name = ?1</ejb-ql>
66: </query>
67: </entity>
The definition of the queryelement is as follows:
<!ELEMENT query (description?, query-method, result-type-mapping?, ejb-ql)>You can see from the listing that the query-methodelement just identifies the name ofthe finder or select method Note that if a finder method is being identified, it is the nameappearing in the local-home (or home) interface; that is, without the ejbprefix On theother hand, if a select method is being identified, there will be an ejbprefix, becauseselect methods never appear in the interfaces of the bean
The result-type-mappingelement applies only if the method identified by methodhas identified a select method, and only then if the EJB QL string returns Entitybean references (that is, if the SELECT [DISTINCT] OBJECT(x)style of select_clausehas been used) The allowable values are Localand Remote, indicating whether theclause should return references through the local or remote interfaces Obviously, if spec-ified, the bean must provide an interface of the appropriate type; if not specified, thebean must provide a local interface, because this is the implied value for the result-type-mappingelement
query-Of course, all of this deployment information can be entered graphically using thedeploytool Figure 7.8 shows some of the equivalent information for Listing 7.12.
deploytool lets CMP deployment informa- tion be defined through
a GUI.
Trang 4The relationships Element
The relationshipselement is defined in the EJB 2.0 DTD as follows:
<!ELEMENT relationships (description?, ejb-relation+)>
That is, it consists of one or more ejb-relationelements These in turn are defined as
<!ELEMENT ejb-relation (description?, ejb-relation-name?, ejb-relationship-role, ejb-relationship-role)>
which is a somewhat curious definition: an optional description, an optional name, andthen precisely two ejb-relationship-roleelements Each of these identifies the rolethat some bean is playing with respect to the relationship
It is possible that the same bean appears in both roles to model recursive relationships.
Note
The ejb-relationship-roleelement is defined as follows:
<!ELEMENT ejb-relationship-role (description?, ejb-relationship-role-name?, multiplicity, cascade-delete?, relationship-role-source, cmr-field?)>
with
<!ELEMENT relationship-role-source (description?, ejb-name)>
You can see that the relationship-role-sourceelement merely identifies an Entitybean by name This element’s name is perhaps somewhat misleading, because it is nei-ther a “source” nor (for that matter) a target within the relationship The navigability ofthe relationship comes from the presence (or not) of the cmr-fieldelement Of course,
at least one of the ejb-relationship-roleelements must have a cmr-fieldspecified,and if both do, the relationship is bi-directional
The choices for the multiplicityelement are either Oneor Many There will be two suchelements in the complete ejb-relationelement, so this is what gives one-to-one, one-to-many, many-to-one, or many-to-many
There is also an optional cascade-deleteelement Perhaps non-intuitively, this is placed
on the “child” (multiplicity = many) side of a relationship
Finally, the cmr-fieldis defined as follows:
<!ELEMENT cmr-field (description?, cmr-field-name, cmr-field-type?)>
Trang 5The cmr-field-nameelement just names the cmr-field(for example,skillsor tionfor the Jobbean) The cmr-field-typeelement is needed only for multi-valuedcmr-fields (for example, skillsfor the Jobbean) and indicates whether the return type
loca-is a java.util.Collectionor java.util.Set
Do not confuse this return type with the allowable return types for select methods These are unrelated areas that just happen to have the same allowable return types.
Trang 6description location Location.name(FK)
name
Skill
description requires
jobs jobs
location location for
Trang 7Location
description
customer ref
Job
description location Location.name(FK)
name
Skill
description requires
jobs jobs
location location for
edit-To actually deploy the enterprise application, use the buildAlland deploybatch scripts
in the day07\builddirectory, or use buildAllto assemble the enterprise application and
deployfrom deploytool
Trang 8should be used only for deploying enterprise applications and for configuring J2EE RIservers.
On the other hand, in the development environment, it can be an error-prone task toattempt to write XML deployment descriptors from scratch If a valid deploymentdescriptor already exists, modifying it (to add a new ejb-refelement or something simi-lar) can often be accomplished, but larger changes (such as adding a completely newbean) will be more difficult without much practice Here,deploytoolcomes into its own
to modify the enterprise application as required (or indeed, to create an enterprise cation from scratch)
appli-When you are happy that the beans and clients in your enterprise application are
correct-ly configured,deploytoolallows the XML deployment descriptor to be saved, forchecking into source code control This is shown in Figure 7.12
deploytool can be
used to configure
rela-tionships through its
Trang 9The Tools, Descriptor Viewer menu option brings up a dialog box displaying the XMLdeployment descriptor; from there, the data can be saved as a file This menu option iscontext sensitive, so what it shows will depend on the node selected in the explorer onthe left pane in the GUI The descriptor viewer dialog should be brought up for eachnode under the enterprise application node, and for the enterprise application node itself.
In the case study, this means for each of the clients, for the dataEntity EJBs, for theagencySession EJBs, and for the agencyapplication node
Deploying a CMP Entity Bean
The enterprise application can be deployed either from the command line (deployscript
in the build directory) or using deploytoolitself
However, before an enterprise application containing CMP Entity beans can be deployed,the default SQL must be generated by using the Deployment Settingsdialog box This
is performed once for each CMP Entity bean, as shown in Figure 7.13
deploytool allows SQL to create the database schema to be generated.
You can see from the figure that J2EE RI generates default SQL It allows the SQL queryfor the finder and select methods to be tuned, and also (the container methodsradiobutton) allows the actual SQL to create the tables, insert rows, and so on to be modified
also The case study does not change any of this default SQL.
Right at the beginning of today’s chapter, it was noted that the schema of the database for the case study had changed from that of Day 6 If one want-
ed to use the exact schema from Day 6, it could have been entered here.Note
Trang 10Also, the dialog allows the underlying tables to be created and deleted on ploy This obviously isn’t appropriate for a production environment, because it woulddelete any data already there It also is not appropriate for the case study, because there isexample data
cre-ates exactly the same schema as that generated by default by J2EE RI It also populates that schema with the same data as in Day 6 and creates views for backwards compatibility.
Note
You will recall that the auxiliary deployment descriptor agency_ea-sun-j2ee-ri.xml
contains all the mappings of the logical dependencies of the EJBs to the physical runtimeenvironment This includes all of the SQL specified in Figure 7.13
It was noted earlier that when creating a new CMP Entity bean, it is often easiest to loadthe enterprise application into deploytooland then save the XML deployment descriptorusing the Tools, Descriptor Viewer menu option/dialog Unfortunately,deploytooldoesnot provide any easy way to write out the auxiliary deployment descriptor, and it isrequired for the command line approach The buildAllscript calls the addJ2eeRiToEar
script that does precisely this
The only real option is to save the agency.earfile once modified, and then use a tool,such as WinZip, to load up the EAR file The auxiliary deployment descriptor can beextracted from that
Patterns and Idioms
This section presents some patterns and idioms that relate to CMP Entity beans You’llrecognize some of the points made here; they were made earlier in the “ContainerManaged Relationships” section
Normalize/Denormalize Data in ejbLoad()/ejbStore()
Under CMP, theejbLoad()and ejbStore()methods don’t have very much (or indeedanything) to do; the interactions with the persistent data store are done by the EJB con-tainer
However, it may be that the physical schema of the persistent data store (especially ifthat persistent data store is an RDBMS) does not correspond exactly with the logicalschema of the Entity bean
Trang 11For example, the Applicanttable defines two columns—address1and address2.However, at least conceptually, the ApplicantEntity bean has a vector field of address,
of type String[]; there could be many lines in the address(and it’s just that the cal schema of the persistent data store constrains the size of this vector to 2):
physi-Santa Claus
No 1 Grotto Square (line 1) Christmas Town (line 2) North Pole (line 3) The World (line 4) Earth (line 5) The Solar System (line 6, and so on …)Because the ejbLoad()method is called after the EJB container has loaded the data, itmay renormalize the data In other words, the data in the two cmp-fields of address1and address2can be converted into the String[] addressfield The bean’s clients’ view(as presented by the methods of the local interface) is that the addressfield is a vector.Conversely, the ejbStore()method, called just before the EJB container updates thedata, can denormalize the data In other words, the data in the addressvector field can
be “posted” back to the address1and address2 cmp-fields
Although the EJB specification allows cmp-fields to be exposed in the local (or remote)interface of a CMP Entity bean, there are problems with doing so Because the settermethod that corresponds to the field is generated by the EJB container, it is not possible
to perform any application-level validation
Instead, it is better to create a shadow setter method, have it do any validation, and thendelegate to the actual cmp-fieldsetter method
You may also want to create a shadow getter method This would allow you symmetry inthe names of the methods, and you could also perhaps do some caching of values orother application-level logic
As an example, instead of exposing the getter and setter methods for the descriptioncmp-fieldof the Jobbean, you might have a local interface of
package data;
import javax.ejb.*;
// imports omitted public interface JobLocal extends EJBLocalObject { String getDescriptionField();
void setDescriptionField(String description);
Trang 12// code omitted }
with a corresponding implementation of
} public abstract String getDescription();
public abstract void setDescription(String description);
}
Don’t Expose cmr-fields
Although the EJB specification allows cmr-fields to be exposed in the local interface of
a CMP Entity bean, it may be best not to There are two reasons why exposing the fieldcauses problems, both related to the returned collection from the getter method of
cmr-a cmr-field:
• The first is that this returned collection is mutable A client can change of theEntity bean’s relationships with other beans by manipulating this collection Inother words, the bean’s state is changed without it being aware
• The second is that the returned collection becomes invalid when the transactioncontext changes This is actually good that this is so, but it is a subtle point, andsome developers might not appreciate it if less than familiar with EJB transactions(making debugging their application somewhat tricky)
An alternative to exposing the setter method of a cmr-fieldwould be for the bean tooffer alternative methods, such as addXxx()and removeXxx(), on the bean itself andhave these call the setter method An alternative to exposing the getter method would be
to expose a shadow method called something like getXxxCopy() This would create acopy of the collection The method name suggests to the client that they will not be able
to change the relationships of the bean Indeed, the returned collection could even bemade immutable
Trang 13As an example, instead of exposing the getter and setter methods for the skills cmp-fieldof the Jobbean, you might have a local interface of
package data;
import javax.ejb.*;
import java.util.*;
// imports omitted public interface JobLocal extends EJBLocalObject { Collection getSkillsCopy();
void addSkill(SkillLocal skill);
void removeSkill(SkillLocal skill);
// code omitted }
with a corresponding implementation ofpackage data;
import javax.ejb.*;
import java.util.*;
// imports omitted public abstract class JobBean implements EntityBean { public Collection getSkillsCopy() {
List skills = new ArrayList();
for(Iterator iter = getSkills().iterator(); iter.hasNext(); ) { skills.add(iter.next());
} return Collections.unmodifiableList(skills);
} public void addSkill(SkillLocal skill) { getSkills().add(skill);
} public void removeSkill(SkillLocal skill) { getSkills().remove(skill);
} public abstract Collection getSkills();
public abstract void setSkills(Collection skills);
// code omitted }
Enforce Referential Integrity Through the Bean’s Interface
Entity beans represent the domain layer in the n-tier architecture, and Entity beans have tionships among themselves If a method in a bean’s interface has an argument of some bean(usually for a relationship), this bean should be defined via the local reference rather than byits primary key In other words, referential integrity is effectively enforced; the client guaran-tees that the bean exists, because it passes through an actual reference to that bean
Trang 14This idiom is honored implicitly for CMP Entity beans that expose their cmr-fields ForCMP Entity beans that provide shadow methods (as discussed earlier), these shadowmethods should still deal with local references to the related beans, rather than identify-ing the related bean by its primary key
This idiom applies equally to BMP Entity beans Indeed, if BMP Entity beans are written to follow this idiom, it becomes that much easier to convert them to CMP.
Note
Use Select Methods to Implement Home Methods
Select methods can only be called by a bean itself, so they act as helper methods A mon place where they are often used is in implementing home methods
com-For example, the Jobbean could have provided a home interface to count the number ofjobs advertised This could have been implemented as follows:
with a corresponding implementation of
} public abstract Collection ejbSelectAllJobs();
// code omitted }
Trang 15The ejbSelectAllJobs()EJB QL query string would be simplySELECT OBJECT(j)
FROM Jobs AS j
EJB QL does not (yet) support a SELECT COUNT(*) syntax, so this is the only way of performing counts (other than resorting to direct access to the data store).
Note
Gotchas
The following is a quick checklist of “gotchas” to help you with your implementation:
• If the primary key is composite, a custom primary key class must be defined Thefields of this class must be publicand must correspond in name and type to cmp- fields of the bean class
• cmp-fieldand cmr-fieldfields must begin with a lowercase letter, (so that it can
be capitalized in the corresponding getter and setter method names)
• If a collection is returned from a cmr-field’s getter method, it must not be fied other than through Iterator.remove() (see EJB specification, section10.3.6.1)
modi-• Collections returned by getter methods cannot be used outside of the transactioncontext in which they were materialized
• If a bean has no relationships, the Collectionreturned by the cmr-field’s gettermethod will be empty, it will not be null Conversely, if calling a cmr-field’s set-ter method,nullcannot be used; instead an empty collection (such as
Collections.EMPTY_LIST) must be passed in
• EJB QL strings are in single quotes!!!
• EJB QL strings define placeholders as ?1,?2, and so on (rather than the JDBC tax of just ?) This allows the arguments of the corresponding finder or selectmethod to be bound in more than once
syn-• When comparing strings in EJB QL, the strings must be identical to be equal (This
is different from SQL where trailing whitespace is usually ignored.)
• An EJB QL empty string is ‘’(0 characters) Some RDBMS treat this as a null
string, so beware! (See EJB Specification, section 11.2.9.)
Trang 16Summary
Well done! In three days (Days 5, 6, and 7), you’ve covered pretty much everything youneed to know about writing EJBs There’s a little mopping up of relatively minor issuestomorrow, but you now well and truly have the essentials under your belt
Today you saw how the n-tier architecture is subtly revised again, with the responsibilityfor persistence delegated downwards (into subclasses) to the EJB container-generatedsubclasses of the CMP Entity bean You also learned that the lifecycle for CMP Entitybeans is substantially the same as BMP Entity beans and, in general, there is less coding
to be done in the lifecycle methods (ejbCreate(),ejbLoad(),ejbStore(), and
ejbRemove())
You now know that cmp-fields are defined in the deployment descriptor and correspond
to primitive and to Serializableobjects They are represented in the CMP bean class asabstract getter and setter methods You also know that cmr-fields work very much thesame way but deal with references to the local interfaces of other Entity beans (or collec-tions thereof) This is what makes local interfaces the basis of container-managed rela-tionships
Finally, you saw how to construct EJB QL queries and how to relate them to both findermethods and to the helper select methods
Q&A
Q What does CMP stand for?
A CMP stands for Container Managed Persistence.
bean’s interfaces?
A cmp-fieldmethods can appear in any interface; cmr-fieldmethods can appearonly in local interfaces
Q What keywords or features of ANSI SQL does EJB QL not (yet) support?
group by, order by (among others)
Q How are the parameters of a select method defined?
class itself
Trang 17Q How is navigability defined in the deployment descriptor?
A The presence of the cmr-fieldelement indicates navigability
Exercises
The job agency case study defines a complete set of Session beans, and Entity beans All
of the Entity beans except the Applicantbean are implemented using CMP; theApplicantbean has been implemented using BMP The exercise is to implement anApplicantEntity bean to use CMP The source code and deployment descriptors can befound under day07\exercise, and the directory structure is the same as yesterday
In more detail, the fields of the Applicantbean need to be converted into either fields or cmr-fields:
cmp-• login This is the primary key for the ApplicantEntity bean and will be a field.
You should find that the JobCMP Entity bean acts as a good model for your new version
of the Applicantbean One difference is in the primary key The Jobbean required aJobPKbecause it had a composite primary key For your Applicantbean, there is no cus-tom primary key, so you will need to nominate the login cmp-fieldas its primary keyusing the primkey-fieldelement in the deployment descriptor Another related differ-ence is that the Jobbean has to deal with ensuring that its customer cmp-fieldis a valididentifier for a Customer Your Applicantbean will not have this complication
There should be no need to change the Agencyand RegisterSession beans that call theApplicantbean, because it is only the internal implementation that is changing, not theinterfaces
The steps you should perform are as follows:
1 If you didn’t do so earlier today, convert the Agencydatabase to its CMP version.The steps to do this were described in the “A Quick Word about the Case StudyDatabase” section
Trang 182 Re-acquaint yourself with the ApplicantLocalHomeand ApplicantLocalfaces However, these will not need to be changed
inter-3 Update the ApplicantBeanclass; base this on JobBean
4 The CMR relationships that will be built will be bi-directional This is neededbecause, otherwise, the code generated by the J2EE RI fails to compile So, in each
of LocationBeanand SkillBean, uncomment the getApplicants()and
setApplicants()methods Note that these have not been exposed in the respectiveinterfaces
5 Build the enterprise application (agency.earin the jardirectory) and then load itinto deploytool Delete the Applicantbean from the enterprise application, andthen add it in again into the data_entity_ejbs ejb-jar As you add it, you canspecify that it is a CMP bean
6 Specify the appropriate cmp-fields for the new bean
7 Add a many-to-many relationship from Applicantto Skill Make the relationshipbi-directional
8 Add a many-to-one relationship from Applicantto Location Make the ship bi-directional
relation-9 Use the deploytool’s Descriptor Viewer dialog to save the XML deploymentdescriptor
10 Now deploy the enterprise application (from the deploytoolGUI), providing thenecessary auxiliary deployment information in the wizard that is displayed Testyour program by using the AllClientsclient, run with run\runAll
11 Optionally, use WinZip or equivalent to extract the auxiliary deployment descriptorand save as dd\agency_ea-sun-j2ee-ri.xmlfrom the agency.earfile previouslygenerated Then re-build and deploy using build\buildAlland build\deploy.Good luck A working example can be found in day07\agency
Trang 20Developing J2EE Applications
8 Transactions and Persistence
9 Java Messaging Service
Trang 22You spent Day 6 and Day 7, “CMP and EJB QL,” comparing the two different tence approaches offered by EJB in the guise of BMP and CMP Entity beans The BMPEntity beans were implemented using JDBC, but that is only one of a number of tech-nologies offered by J2EE and Java in general Today, you will learn
persis-• How to manage transactions explicitly in EJBs
• How transactions are managed “behind the scenes” in an EJB environment
• Some other persistence technologies other than JDBC—specifically, SQLj andJDO
Overview of Transactions
If you’ve used RDBMS before, or completed a Computer Studies course or read anyother J2EE book, you’ve probably read a section like this one already But read on any-way, if only to be acquainted with some of the J2EE terminology that is used in thisarena
A transaction is an atomic unit of work:
• Atomic unit means indivisible—either every step within the transaction completes
or none of them do
• Work here usually means some modification to data within a persistent data store.
In RDBMS terms, this means one or more INSERT,UPDATE, or DELETEs However,strictly speaking, it also applies to reading of data through SELECTstatements.For a persistent data store to support transactions, it must pass the so-called “ACID” test:
• Atomic—The transaction is indivisible; the data store must ensure this is true.
• Consistent—The data store goes from one consistent point to another Before the
transaction, the data store is consistent; afterwards, it is still consistent
The age-old example is of transferring money between bank accounts This willinvolve two UPDATEs, one decrementing the balance of account #1 and the otherincrementing the balance of account #2 If only one UPDATEoccurs, the transaction
is not atomic, and the data store is no longer in a consistent state
• Isolation—The data store gives the illusion that the transaction is being performed
in isolation Enterprise applications have many concurrent users who are all forming transactions at the same time, so behind the scenes, the data store uses tech-niques, such as locks, to serialize access to the contended data where necessary
per-• Durability—If a transaction completes, any changes made to the data as a result of
that transaction must be durable In other words, if the power were to fail a lisecond after the transaction has completed, the change must still be there whenpower is reconnected
Trang 23Many data stores use transaction logs to address this requirement The transactionlog holds a journal of changes made to the actual data When the transaction com-pletes, the log is written to disk, although the actual data need not be
If you are a Windows user, you may know that Windows NT, 2000 and XP support a filesystem type called NTFS This replaces the FAT and FAT32 filesystem types used in Windows 95, 98, and ME.
Microsoft often say that NTFS is more reliable, although slightly slower than FAT/FAT32 This is because NTFS has a built-in transaction log, whereas FAT/FAT32 does not.
Note
Many data stores allow transactions to be started explicitly using a syntax such as thefollowing:
begin transaction t1
where t1is the (optional) name transaction Transactions are completed using either
commit(make changes permanent) or rollback(undo all changes made in the tion, and revert all data back to the state before the transaction began) Many data storeswill use
transac-commit transaction t1
and
rollback transaction t1
Some data stores support the concept of nested transactions, whereby (for a
single user) one transaction can be started while another transaction is still
in progress In other words, two begin transaction s can be submitted out a commit or rollback between them.
with-However, the EJB specification and many others support only flat
transac-tions, whereby one transaction must be completed before another is begun
(see EJB specification, section 17.1.2) Consequently, nested transactions are not considered further.
Note
To conclude this short introduction, consider the fragment of SQL shown in Listing 8.1
It transfers $50 from account #20457 to account #19834
Trang 24LISTING 8.1 Example Fragment of SQL to Transfer Money Between Accounts
1: begin transaction transfer_money 2:
3: update account 4: set balance = balance - 50 5: where account_id = 20457 6:
7: update account 8: set balance = balance + 50 9: where account_id = 19834 10:
11: commit transaction transfer_money
In effect, there are two different types of commands:
• Lines 1 and 11 demarcate the transaction
• Lines 3–5 and 7–9 modify data
A conventional RDBMS processes all of the SQL in Listing 8.1, but it is performing twodifferent roles in doing so To understand and process the transaction demarcation com-
mands, it is acting as a transaction manager To understand and process the remaining lines, it is acting as a resource manager.
In the EJB specification, these two responsibilities are split In principle, you can think
of the EJB container as acting as the transaction manager, and the persistent data store
acting only as the resource manager The term transaction coordinator is sometimes used
instead of transaction manager because there could be more than one resource whosetransactions are being coordinated
Splitting the responsibilities of transaction management and resource management hastwo consequences For the bean provider, it means that to start a transaction, the beanmust interact both with the EJB container and with the persistent data store The formerinteraction is largely implicit because it is configured through the deployment descriptor(and as you know, the latter interaction is implicit if CMP Entity beans are used) Theother consequence is that, for the persistent data store, it must defer all transaction con-trol responsibility up to the EJB container Behind the scenes, there is some quite sophis-ticated communication going on; you’ll learn a little about this activity later on today
Container-Managed Transaction Demarcation
You’ve spent the last three days writing and deploying EJBs without really having toworry too much about transactions This isn’t to say that there have been no transactions
in use; far from it Every interaction with the database performed in the case study has
Trang 25involved transactions However, the Session and Entity beans deployed have used
con-tainer manager transaction demarcation (here referred to as CMTD, though the
abbrevi-ation isn’t used in the EJB specificabbrevi-ation) Informabbrevi-ation in the deployment descriptor cates when the EJB container should start and commit transactions
indi-Figure 8.1 shows a diagram that you saw first on Day 6
local client
home
remote
local home
local
location transparency
security and transactions
home stub
remote stub
This shows how the EJB proxy objects (those implementing the javax.ejb.EJBObject
or javax.ejb.EJBLocalObjectinterfaces) implement the transaction semantics This isone of the reasons that a bean must never implement its own remote interface To do sowould mean that it could unwittingly return a reference to itself as a Remoteinterface,subverting any security and transaction checks performed by its proxy
Listing 8.2 shows a fragment of the deployment descriptor for the AdvertiseJobSessionbean from Day 7
10: </enterprise-beans>
11: <assembly-descriptor>
12: <container-transaction>
Trang 2622: </method>
23: <trans-attribute>Required</trans-attribute>
24: </container-transaction>
25: … lines omitted … 26: </assembly-descriptor>
27: </ejb-jar>
As you have seen over the last three days, the enterprise-beanselement consists ofsessionor entityelements The session element has a transaction-type element which,under CMTD, should have the value of Container For entity elements, the transaction-type is not specified because entity beans must always be deployed using CMTD, so it isimplicit
Each method of the remote interface must be present in a container-transactionment The same is true of the methods in the home interface The relevant DTD defini-tions that govern the structure of the deployment descriptor are as follows:
ele-<!ELEMENT ejb-jar (description?, display-name?, small-icon?, large-icon?, enterprise-beans, relationships?, assembly-descriptor?, ejb-client-jar?)>The assembly-descriptorelement is defined as follows:
<!ELEMENT assembly-descriptor (security-role*, method-permission*,
➥container-transaction*, exclude-list?)>
You can see here that assembly-descriptorelement is all about providing the tion used to create the EJB proxy objects The security-role,method-permission, and exclude-listelements are security related, and the container-transactionelementobviously defines transaction-related information
informa-The security-related elements of the assembly-descriptorelement are not consideredfurther here However, the container-transactionelement is relevant to the discussion
It is defined in the DTD as follows:
<!ELEMENT container-transaction (description?, method+, trans-attribute)>and the methodelement is defined as
<!ELEMENT method (description?, ejb-name, method-intf?,
➥method-name, method-params?)>
Trang 27So, a container-transactionelement identifies one or more methods The methodment identifies a method in the home or remote interface; the method-intfelement isonly needed in those rare occasions when there happens to be a method of the samename in both the home and remote interfaces The method-namemust be specified,although the value of *can be used as a convenient shortcut to indicate all methods The
ele-method-paramselement is optional and is used to distinguish between overloaded sions of the same method name If not specified, the methodelement identifies all over-loaded versions of the method with the specified name
ver-Finally, the bit that really matters The trans-attributeelement indicates the
transaction-al characteristics to be enforced when the specified method is invoked A transaction may
or may not be in progress; in the terminology of the EJB specification, there may or may
not be a current valid transactional context When a method is invoked, the EJB container
needs to know what should occur For example, if there is no transaction in progress, is oneneeded to execute the method? Should a transaction be started automatically if there isn’t
one? Perhaps a transaction can be started even if another one is in progress? And so on.
There are six possible values; their semantics are shown in Table 8.1
T ABLE 8.1 Different CMTD Semantics Are Indicated by the trans-attribute Element
does not support an external transaction not specify the transactional coordinator Any current transaction context semantics of the method.
will be suspended for the duration of the method.
current transaction context will be used
if present; otherwise, one will be created.
like Required ) Otherwise, use unspecified NotSupported This makes transaction context (acts like NotSupported ) the Supports a highly dubi-
ous choice The method must guarantee to work in the same way whether or not there is a transaction context available.
existing valid transaction context will be example, for a bean that suspended for the duration of the method generates unique IDs or for
a bean that writes to a log).
Trang 28Mandatory A valid transaction context must exist; an Useful for helper beans’
exception will be thrown by the EJB container methods, designed to be otherwise The transaction context will be used called only from another
bean.
Never There must be no current transaction context Acts as NotSupported.
An exception will be thrown by the EJB container otherwise The method invokes with
an unspecified transaction context.
For Entity beans, only the Required,RequiresNew, and Mandatory trans-attributeues are recommended The problem with NotSupported,Never, and (if invoked with nocurrent transaction context) Supportsis that, in addition to performing the businessmethod, the EJB container must also perform the ejbLoad()and ejbStore()methods.These will be performed with the same transactional context as the business method,
val-which is to say, with no transactional context What might happen then is somewhat
unde-fined, as the EJB specification is at pains to point out Indeed, it goes so far as to list (insection 17.6.5) four or five different ways in which the EJB container might decide to act
T ABLE 8.1 Continued trans-
Never use NotSupported, Never, or Supports as trans-attribute ues with Entity beans.
val-Caution
As usual, the deploytoolGUI can also be used to configure the information within thedeployment descriptor, as shown in Figure 8.2
You are likely to find that the vast majority of your beans’ methods will use the
Required trans-attributevalue Indeed, this is the value that has been used in the casestudy over previous days
Although CMTD means that the EJB container automatically starts, suspends, and pletes transactions, this is not to say that the beans themselves cannot influence the trans-actions After all, if an Entity bean hits an error condition that means that the transactionshould be aborted, it needs some way to indicate this to the EJB container As an exam-ple, consider the hackneyed example of withdrawing money from a bank account If thebalance would go into the red, (or perhaps more likely, beyond an overdraft limit), theEntity bean that represents the account would want to indicate that the transaction should
com-be aborted
Trang 29To do this, the bean can use two transaction-related methods provided by itsEJBContext
In the case of a Session bean, this will be the javax.ejb.SessionContextpassed inthrough the setSessionContext()method, and for an Entity bean, this will be the
javax.ejb.EntityContextpassed in through setEntityContext() To remind you,Figure 8.3 shows a UML class diagram illustrating the methods provided by these inter-faces
back to the different EJB roles you learned about back on Day 2, “The J2EE Platform and Roles.” The intention is that the bean provider completes just the information in the enterprise-beans element, while the application assembler completes the information under the assembly-descriptor This allows an EJB component to be used in different applications, with different transaction and security requirements.
In contrast, the deploytool does not differentiate between the two roles;
the transaction (and security) information are just two of the seven tabs on the right side of the GUI, providing information about the selected EJB; the other five tabs pertain to information found under the enterprise-beans
element.
Note
Trang 30To cause the transaction to be aborted, the CMTD bean can call setRollbackOnly().This instructs the EJB container to prevent the transaction from being committed Thebean cannot rollback the transaction directly, because the transaction itself is “owned” bythe EJB container, not the bean The getRollbackOnly()method obviously just indi-cates whether the transaction has been marked for rollback.
There is one other transaction-related method in EJBContext, namelygetUserTransaction() However, this cannot be called by a CMTD bean, and anyattempt to do so will result in the EJB container throwing a
java.lang.IllegalStateException.
The EJBContext vides access to the cur- rent transaction.
pro-interface
EJBContext
+getEJBHome():EJBHome +getEJBLocalHome():EJBLocalHome +getEnvironment():Properties +getCallerIdentity():Identity +getCallerPrincipal():Principal +IsCallerInRole(Identity:Identity):boolean +IsCallerInRole(s:String):boolean +getUserTransaction():UserTransaction +setRollbackOnly():void
+getRollbackOnly():boolean
interface
EntityContext
+getEJBLocalObject():EJBLocalO +getEJBObject():EJBObject +getPrimaryKey():Object +setEJBLocalObject(pO:EJBObje
interface
SessionContext
+getEJBLocalObject():EJBLocalO +getEJBObject():EJBObject
interface
javax.transaction.UserTransaction
+begin():void +commit():void +getStatus():int +rollback():void +setRollbackOnly():void +setTransactionTimeout(:int):void !
interface
javax.transaction.Status
+STATUS_ACTIVE:int +STATUS_MARKED_ROLLBACK:int +STATUS_PREPARED:int +STATUS_COMMITTED:int +STATUS_ROLLEDBACK:int +STATUS_UNKNOWN:int +STATUS_NO_TRANSACTION:int +STATUS_PREPARING:int +STATUS_COMMITTING:int +STATUS_ROLLING_BACK:int
manag-If your bean does need more fine-grained control over transactions, the bean must bedeployed using bean-managed transaction demarcation This is discussed next
Trang 31Bean Managed Transaction Demarcation
If an EJB is deployed using bean managed transaction demarcation (here referred to as
BMTD, though this abbreviation isn’t used in the EJB specification itself), the EJB tainer allows the bean to obtain a reference to a javax.transaction.UserTransaction
con-object using the EJBContext You can see this in Figure 8.3
Motivation and Restrictions
An EJB might need to be deployed under BMTD if the conditions on which a transaction
is started depend on some programmatic condition It could be that one method starts thetransaction and another method completes the transaction
However, the cases where BMTD is needed are few and far between Indeed, they are sorare that the EJB specification limits BMTD to Session beans Entity beans can only bedeployed with CMTD This makes sense because Entity beans represent persistent trans-actional data; the transaction context should be as deterministic as possible
Moreover, if a stateless Session bean starts a transaction, it must also commit that action before the method completes After all, the stateless Session bean will have nomemory of the client that just invoked its method after that method completes, so onecannot expect that the transaction context is somehow miraculously preserved If youwrite a BMTD stateless Session bean that does not commit its own transaction, the EJB
trans-container will rollback the transaction and throw an exception back to the client
(java.rmi.RemoteExceptionfor remote clients, or javax.ejb.EJBExceptionfor local)
Indeed, even with stateful Session beans, there is a restriction Any current transaction inprogress when the BMTD Session bean is called will be suspended by the EJB container,not propagated to the BMTD bean It is possible that, from the bean’s perspective, there
is a current transaction, but that would refer to any transaction not committed when amethod on that bean was last called
Using the Java Transaction API
When a Session bean is deployed under BMTD, there is an implementation choice as tohow it should manage its transactions If interacting solely with an RDBMS, the Sessionbean can manage the transactions directly through the JDBC API Alternatively, it canuse the Java Transaction API, defined by the classes and interfaces in the javax.trans- actionand the javax.transaction.xapackages The latter is to be preferred, if onlybecause transactional access to Java Messaging Service resources (you’ll be learningmore about these tomorrow and the day after) can only be performed through the JTAAPI Equally, servlets can also use the JTA API
Trang 32For a Session bean to start a transaction, it should first call the getUserTransaction()method of its SessionContext You’ll recall that this was the method that throws anexception under CMTD, but it is the centerpiece of transaction control under BMTD.Obtaining a UserTransactiondoes not mean that a transaction has been started Rather,
it must be started using the begin()method The transaction can then be completedusing either the commit()or the rollback()method The current status can also beobtained using getStatus() This returns an intwhose meaning is defined by theconstants in the javax.transaction.Statusinterface Some of the most common statusvalues are shown in Table 8.2
TABLE 8.2 Some of the Constants Defined in javax.transaction.Status
STATUS_NO_TRANSACTION No transaction is active tran.begin() to start new
transaction.
STATUS_ACTIVE A transaction is active and can Use resource manager.
tran.rollback() to rollback STATUS_MARKED_ROLLBACK A transaction is active, but has tran.rollback()
been marked for rollback Any attempt to commit it will result
in a javax.transaction.
RollbackException being thrown.
The Java 2 Platform Enterprise Edition Specification, the document that
defines the interoperability of all the technologies that make up the J2EE
plat-form, only discusses transaction interoperability in the context of the JTA API.
If nothing else, the semantics of intermixing JDBC and JTA calls are not exhaustively defined, so this should be avoided to minimize chances of portability problems if moving to a different vendor’s EJB container.
Note
There are more constants in the Status interface than those listed in Table 8.2 Later today, (in the “Transactions: Behind the Scenes” section), you’ll be learning about some of the “under-the-covers” mechanics of transaction management; the full list is presented there.
Note
Listing 8.3 shows a possible implementation for the updateDetails()method of
AdvertiseJobbean using BMTD
Trang 337: public class AdvertiseJobBean extends SessionBean { 8: public void updateDetails (String description,
➥String locationName, String[] skillNames) { 9:
10: int initialTranStatus = beginTransactionIfRequired();
11:
12: if (skillNames == null) { 13: skillNames = new String[0];
14: } 15: List skillList;
16: try { 17: skillList = skillHome.lookup(Arrays.asList(skillNames));
18: } catch(FinderException ex) { 19: error(“Invalid skill”, ex, initialTranStatus);
➥ // throws an exception 20: return;
21: } 22:
23: LocationLocal location=null;
24: if (locationName != null) { 25: try {
26: location = locationHome.findByPrimaryKey(locationName);
27: } catch(FinderException ex) { 28: error(“Invalid location”, ex, initialTranStatus);
➥ // throws an exception 29: return;
30: } 31: } 32:
40: private int beginTransactionIfRequired() { 41:
42: UserTransaction tran = this.ctx.getUserTransaction();
43: // start a new transaction if needed, else just use existing.
44: // (simulates trans-attribute of REQUIRED) 45: int initialTranStatus;
Trang 3446: try { 47: initialTranStatus = tran.getStatus();
48: switch(initialTranStatus) { 49: case Status.STATUS_ACTIVE:
50: // just use 51: break;
52: case Status.STATUS_NO_TRANSACTION:
53: // create 54: try { 55: tran.begin();
56: } catch(NotSupportedException ex) { 57: // shouldn’t happen (only thrown if asking for nested exception 58: // and is not supported by the resource manager; not attempting 59: // to do this here).
60: throw new EJBException(
➥ “Unable to begin transaction”, ex);
61: } 62: break;
63:
64: // code omitted; other Status’ covered later 65:
66: default:
67: throw new EJBException(
68: “Transaction status invalid, status = “ +
➥ statusAsString(initialTranStatus));
69: } 70: } catch(SystemException ex) { 71: throw new EJBException(“Unable to begin transaction”, ex); 72: }
73:
74: return initialTranStatus;
75: } 76:
89: if (tran.getStatus() == Status.STATUS_MARKED_ROLLBACK) { 90: tran.rollback();
Trang 3591: } else { 92: tran.commit();
93: } 94: } catch(Exception ex) { 95: throw new EJBException(
➥ “Unable to complete transaction”, ex);
96: } 97: } 98: } 99: }
The two helper methods,beginTransactionIfRequired()and
completeTransactionIfRequired(), isolate the actual transaction management code, so
it can be reused across different methods
Deploying a BMTD Bean
Of course, when deploying a bean under BMTD, the deployment descriptor should cate a transaction-typeelement of Bean, and you will not need any container-transaction elements under the application-assemblyelement Figure 8.4 shows
indi-deploytoolfor the AdvertiseJobbean, indicating this fact
Trang 36Incidentally, if a BMTD Session bean calls getRollbackOnly()or setRollbackOnly()
on its SessionContext, the EJB container will throw ajava.lang.IllegalStateException This is reasonable; if a BMTD has access to the UserTransactionobject, it has no need for these methods Instead, it can call thegetStatus()method of UserTransaction, and explicitly call rollback()if needed
Client-Demarcated Transactions
As well as Session beans managing their own transactions, it is also possible for clients
to initiate the transaction and have it propagate through to the EJBs Here, “client” meanseither an application client written using the Swing GUI (such as you have seen in thecase study), or it could equally refer to a Web-based client implemented using servletsand JSPs
For either of these clients, the EJB architecture requires that a UserTransactioncontextcan be obtained via JNDI, bound under the name of java:comp/UserTransaction Sothe code fragment shown in Listing 8.4 will do the trick
LISTING 8.4 Obtaining a UserTransaction Object from JNDI
1: // assuming:
2: // import javax.naming.*;
3: // import javax.transaction.*;
4: InitialContext ctx = new InitialContext();
5: UserTransaction tran = (UserTransaction)
If that philosophical argument does not appeal, perhaps this might A rogue client could
be coded such that it begins a transaction, interacts with (and therefore ties up) variousresources, such as Entity beans, and then not commit This could seriously impact theperformance of your application
Exceptions Revisited
On Days 5 and 6, you learned the appropriate exceptions for your EJB to throw In summary
Trang 37However, CMTD beans may decide to mark the current transaction for rollback, meaningthat the “owner” of the transaction (the EJB container or some BMTD bean) will beunable to commit that transaction.
If a BMTD bean hits an error condition, it has a choice Because it “owns” the tion, it can simply do a rollback Alternatively, it might elect to keep the transactionactive
transac-If a system-level exception is thrown by a bean, this does have consequences for any
cur-rent transaction If any bean throws a system exception, the EJB container will mark thecurrent transaction for rollback If that bean happens to be a CMTD bean, and the EJBcontainer started a transaction just before invoking the CMTD method (as a result of a
Requiredor RequiresNew trans-attribute), the EJB container will actually rollbackthat transaction
To summarize,
• An application-level exception may or may not leave the current transaction active;
use getStatus()or getRollbackOnly()to find out
• A system-level exception will either mark the current transaction for rollback oreven do the rollback
One last thing on transactions and exceptions Most of the exceptions in javax.ejb
(CreateException,RemoveException, and so on) are application exceptions Some ofthese, especially with CMP Entity beans, are raised by the EJB container itself Ratherunhappily, the EJB specification does not mandate whether these application exceptionsshould mark any current transaction for rollback (see section 10.5.8) Instead, it just indi-cates that the getStatus()or getRollbackOnly()methods should be used to determinethe status of the current transaction In practical terms, what this means is that differentEJB containers could have different implementations, compromising portability
Trang 38Extended Stateful Session Bean Lifecycle
Occasionally, there is a need for a stateful Session bean to have visibility as to theprogress of the underlying transaction Specifically, a bean might need to know
• Has the transaction started?
• Is the transaction about to complete?
• Did the transaction complete successfully or was it rolled back?
For example, consider the age-old example of a ShoppingCartbean In its purchase()method, it is likely to modify its internal state Perhaps it holds its contents in ajava.util.Listcalled currentContents On purchase(), it might move the contents
of currentContentsto another java.util.Listcalled recentlyBought
Suppose, then, that the transaction that actually modifies the persistent data store fails tocomplete Maybe the shopper doesn’t have enough limit left on his or her credit card.Because Session beans are not transactional, the ShoppingCartbean needs to know that
it should reset its internal state back to the beginning of the transaction In other words, itneeds to move the contents of the recentlyBoughtlist back over to currentContents.Obviously, there is no issue for stateful Session beans deployed under BMTD, becausethey are the owner of the transaction anyway and know when the tran.begin()andtran.commit()methods will be invoked But for CMTD Session beans, there is an issue.The EJB specification addresses this by extending the lifecycle of the bean If a statefulSession bean implements the javax.ejb.SessionSynchronizationinterface, three addi-tional lifecycle methods are defined and will be called at the appropriate points:
• afterBegin() The transaction has just begun
• beforeCompletion() The transaction is about to be committed
• afterCompletion(boolean) The transaction has completed The booleanment has the value trueto indicate that the transaction was committed, or falsetoindicate that the transaction was rolled back
argu-Figure 8.5 is a reworking of argu-Figure 5.14 that you saw back on Day 5 It shows the ful Session bean’s view of its lifecycle (The client’s view and the actual lifecycle man-aged by the EJB container are unchanged)
Trang 39There are analogies here also with SQL, where the afterBegin()corresponds to a
SELECT … WITH HOLDLOCKstatement, and beforeCompletion()corresponds to the
interface gives the
stateful Session bean
visibility to the
trans-actions managed under
CMTD.
Bound to client Pooled
Passivated
create/ejbCreate remove/ejbRemove
pool too small/setSessionContext
[too many active]
TX business method
[business method or remove invoked]/ejbActivate
commit/beforeCompletion afterCompletion(true) Ready
Ready in xact
Trang 40Transactions: Behind the Scenes
The EJB specification starts off by listing nine goals The second of these reads as follows:
“The Enterprise JavaBeans architecture will make it easy to write applications: Application developers will not have to understand low-level transaction and state management details, multi-threading, connection pooling, and other complex low- level APIs.”
The EJB specification (downloadable fromhttp://java.sun.com/products/ejb/index.html) largely succeeds in addressing thisgoal—as a developer, you really do not need much knowledge about how transactionsare managed The fact that this book only covers transactions today is testament to that.Nevertheless, like most technical topics, it can be helpful to have an insight as to what isgoing on “behind the scenes.” But if you want to skip this material and make a shorterday of it, please do so You can always re-read at a later date if you find yourself wanting
to know more
Transaction Managers, Resource Managers, and 2PC
You already know about the terms resource manager and transaction manager (or action coordinator) In most EJB applications, an RDBMS will take the place of aresource manager, and the EJB container itself will be the transaction manager
trans-This division of responsibilities is required because in an EJB architecture, the data used
by Session beans or represented by Entity beans may reside in more than one persistentdata store For example, one Entity bean might map onto an Oracle RDBMS, and anoth-
er Entity bean may map onto a Sybase RDBMS, as shown in Figure 8.6 (The numberswill be explained shortly.)
The J2EE platform separates resources and transaction man- agers.
client
session bean
entity bean entity bean