Vous êtes sur la page 1sur 743

Guerrilla Java

Student Manual
Copyright © 2001, DevelopMentor, Inc.
FW089 8-13-01
Guerrilla Java

Contents

1 HTTP .................................................................... 17
HTTP Basics .........................................................................19
Using HTTP As RPC............................................................... 20
Using HTTP........................................................................ 22
HTTP Endpoints .................................................................. 24
HTTP Messages ................................................................... 28
HTTP Requests ................................................................... 32
HTTP Responses .................................................................. 36
HTTP Redirection ................................................................ 38
More HTTP ...........................................................................41
HTTP Connections ............................................................... 42
HTTP Session Management ..................................................... 44
HTTP Security .................................................................... 46
Client Code ..........................................................................49
java.net.URL ..................................................................... 50
java.net.URLConnection and friends ......................................... 52
2 Servlets i ............................................................... 57
Servlets Introduction ..............................................................59
Servlets............................................................................ 60
Web Applications ................................................................ 62
Writing Servlets .................................................................. 66
Writing a Servlet ................................................................. 70
HTTP Request Processing ....................................................... 74
Response Processing............................................................. 76
Helper Classes and Interfaces.................................................. 78
Request Dispatching From Servlets.............................................81
Request Dispatching ............................................................. 82
Forwarding Data in the Request ............................................... 86
Request Dispatching Issues ..................................................... 88
Configuring Web Applications....................................................91
Configuration ..................................................................... 92
Container Configuration ........................................................ 94
Application Configuration ...................................................... 96
3 JSP......................................................................101
Introduction to JSP .............................................................. 103
Why JSP? .........................................................................104
How does it work? ..............................................................106
Intrinsic Variables...............................................................108
Producing Output ...............................................................110

Copyright © 2001, DevelopMentor Inc. iii


Guerrilla Java

Script .............................................................................112
Directives ........................................................................116
JSP Actions and JavaBeans..................................................... 119
What are beans?.................................................................120
jsp:useBean ......................................................................124
Accessing Bean properties .....................................................128
4 EJB Introduction .....................................................133
Introduction to the EJB model ................................................ 135
The EJB Way .....................................................................136
Remote Procedure Call ........................................................140
Commingling of concerns ......................................................142
Java Remote Method Protocol (JRMP) .......................................144
Internet Inter-Orb Protocol (IIOP) ............................................146
Introduction to the EJB Programming Model ............................... 149
EJB programming model .......................................................150
Writing a Bean...................................................................152
A Better Way ....................................................................158
Bean creation....................................................................162
Deploying.........................................................................164
Client view.......................................................................168
5 XML .....................................................................171
Introduction To XML ............................................................. 173
What is XML? .....................................................................174
What is XML Schema?...........................................................178
'Programming' XML ..............................................................182
Programming XML with SAX .................................................... 185
SAX ................................................................................186
ContentHandler .................................................................188
Parsing a document.............................................................190
InputSource ......................................................................192
Programming XML with DOM ................................................... 195
DOM ...............................................................................196
DOM logical structure ..........................................................198
DOM Interfaces ..................................................................200
Node Interface ..................................................................202
Document Interface ............................................................204
Using XPath........................................................................ 207
XPath .............................................................................208
Location Path....................................................................210
Location Steps...................................................................212
6 JDBC....................................................................217
JNDI ................................................................................. 219
Naming and Directory Services ...............................................220
JNDI architecture ...............................................................224
The initial context ..............................................................226
Data access with JDBC .......................................................... 229

iv Copyright © 2001, DevelopMentor Inc.


Guerrilla Java

What is JDBC?....................................................................230
Programming JDBC............................................................... 233
JDBC programming model .....................................................234
Connections......................................................................236
Simple statements ..............................................................242
Results............................................................................244
More complex statements and results .......................................248
Extending ResultSets ...........................................................252
Optimizations....................................................................256
7 Transactions ..........................................................261
Transactions....................................................................... 263
Data access challenges.........................................................264
Transaction basics ..............................................................266
Local transactions ..............................................................270
Transaction tensions ...........................................................274
Transaction isolation ...........................................................276
Transactions and time..........................................................280
Distributed transactions ........................................................ 285
Distributed transactions .......................................................286
8 EJB Declarative Transactions .....................................293
Managed Transactions ........................................................... 295
Managed transactions ..........................................................296
Managed transaction types ....................................................300
Container-managed transactions .............................................302
CMT beans and transaction outcome ........................................308
Bean-managed transactions ...................................................314
BMT beans and transaction outcome.........................................320
CMT stateful session beans and TX outcome................................324
9 State Management...................................................329
Managing State in a Web Application......................................... 331
Managing conversational state................................................332
State is held at the server .....................................................336
Session Lifecycle ................................................................340
Session Events ...................................................................342
Session Lifetime.................................................................344
Distributable Sessions ..........................................................346
Cookies ...........................................................................350
Managing State in the Face of Threads ...................................... 353
Servlets and Threads ...........................................................354
Protecting State.................................................................358
Protecting Application State ..................................................360
Protecting Session State .......................................................362
javax.servlet.Singlethreadmodel .............................................364
10 EJB Session Beans ................................................367
EJB Sessions ....................................................................... 369

Copyright © 2001, DevelopMentor Inc. v


Guerrilla Java

Two bean types .................................................................370


Stateless session bean ( ........................................................372
Stateless session beans and JITA .............................................378
Stateful session bean...........................................................380
Stateful session bean handles.................................................384
Appropriate use of session beans.............................................386
11 XML-based Web Services ........................................389
Web services ...................................................................... 391
What is a web service? .........................................................392
Universal types ................................................................... 395
What is XML Schema?...........................................................396
Schemas and programmatic type .............................................402
Universal protocol ............................................................... 409
Simple Object Access Protocol................................................410
Universal description............................................................ 417
Web Services Description Language (WSDL) ................................418
Universal discovery .............................................................. 423
What is UDDI?....................................................................424
What is stored in UDDI registry? ..............................................426
Programming UDDI ..............................................................430
12 Resource Loaders .................................................437
Resource Loaders ................................................................ 439
Resource Loader Architecture ................................................440
Internal Safety ..................................................................442
Referential Safety ..............................................................444
Dynamic Class Loading .........................................................446
Class Loaders as Namespaces .................................................448
Version Support .................................................................452
Loading Over a Network .......................................................454
Using and Extending Loaders .................................................. 457
Ease of Use.......................................................................458
Using an Explicitly Loaded Class ..............................................460
Using the Context Loader......................................................462
Extending Class Loading .......................................................466
13 Type Information .................................................469
Type Information................................................................. 471
Type Information ...............................................................472
Runtime Type Information.....................................................474
Reflective Modification ........................................................478
Dynamic Proxies.................................................................482
Type-driven services in J2EE ..................................................486
14 EJB Entities ........................................................489
Introduction to entities ......................................................... 491
What is an entity?...............................................................492
Entity bean basics ..............................................................496

vi Copyright © 2001, DevelopMentor Inc.


Guerrilla Java

Entity bean lifecycle ...........................................................502


Container-managed persistence............................................... 507
EJB 1.1 container-managed persistence.....................................508
EJB 2.0 container-managed persistence.....................................514
Bean-managed persistence..................................................... 525
Bean-managed persistence ....................................................526
Issues with entities .............................................................. 531
The danger of entities .........................................................532
Some possible solutions ........................................................534
15 XSLT .................................................................539
Extensible Stylesheet Language: Transformations ( XSLT ) .............. 541
What is XSLT? ....................................................................542
XSLT basics.......................................................................546
XSLT syntax (1) ..................................................................550
XSLT syntax (2) ..................................................................560
XSLT syntax (3) ..................................................................568
16 Platform Security .................................................573
Platform Security ................................................................ 575
SecurityManager ................................................................576
Call Stack and Code Source ...................................................578
Policy .............................................................................580
Default Policy ...................................................................584
Permissions ......................................................................586
Privileged Scopes ...............................................................590
17 Java Distributed Security .......................................593
Introduction to Distributed Security ......................................... 595
The needs of distributed security ............................................596
HTTP authentication mechanisms ............................................598
Secure, encrypted communication ...........................................604
Java distributed security ....................................................... 611
Declarative security for Servlets .............................................612
Declarative authentication for Servlets .....................................614
Declarative integrity/privacy for Servlets ..................................618
Declarative authorization for Servlets .......................................620
Programmatic security in a Servlet/JSP .....................................624
EJB security......................................................................630
18 Tag Libraries.......................................................633
JSP Tag Libraries ................................................................. 635
What is a tag library?...........................................................636
Tag handlers .....................................................................640
Simple Tag .......................................................................642
Iteration Tags....................................................................648
Body Tags ........................................................................652
Nested Tags......................................................................658
Outputting Data .................................................................662

Copyright © 2001, DevelopMentor Inc. vii


Guerrilla Java

Creating Script Objects With Tags ............................................ 665


Defining Scripting Variables ...................................................666
19 Java Messaging ....................................................671
Messaging .......................................................................... 673
Problems with RPC..............................................................674
Messaging is an alternative ....................................................678
Java Messaging Service.......................................................... 683
JMS Features.....................................................................684
JMS programming model .......................................................686
Working with messages ........................................................690
Transactions .....................................................................698
EJB Messaging-driven Beans ................................................... 701
EJB 2.0/JMS integration .......................................................702
Coding a message-driven bean................................................704
20 What's New.........................................................709
New Features in JSP 1.2........................................................ 711
Validation ........................................................................712
Listeners .........................................................................714
Better tag lib support ..........................................................716
Property Verification ...........................................................718
Using Events in a Java WebApplication ...................................... 721
What are Listeners..............................................................722
Writing Listeners ................................................................724
Using Filters in a Java WebApplication ...................................... 727
What is a Filter?.................................................................728
Writing Filters ...................................................................730
Wrapping Request/Response ..................................................734
Filter Configuration.............................................................736
Glossary ............................................................................ 739
Bibliography ....................................................................... 741

viii Copyright © 2001, DevelopMentor Inc.


Guerrilla Java

Figures

Figure 1.1: RPC........................................................................... 21


Figure 1.2: HTTP Endpoints ............................................................ 25
Figure 1.3: HTTP URL with Query String.............................................. 26
Figure 1.4: Request/Response Pair.................................................... 29
Figure 1.5: HTTP Headers and Body................................................... 29
Figure 1.6: HTTP Request............................................................... 33
Figure 1.7: HTTP GET example ........................................................ 34
Figure 1.8: HTTP POST example ....................................................... 34
Figure 1.9: Common Response Codes ................................................. 37
Figure 1.10: 303 and 307 Response Codes............................................ 39
Figure 1.11: Simple Client GET ........................................................ 53
Figure 1.12: Simple Client POST ....................................................... 54
Figure 2.1: Servlet Loading............................................................. 63
Figure 2.2: Executing Servlets ......................................................... 64
Figure 2.3: Servlet Interface ........................................................... 67
Figure 2.4: HTTP Servlet Code ......................................................... 71
Figure 2.5: Our Servlet Code ........................................................... 72
Figure 2.6: Request Processing ........................................................ 75
Figure 2.7: HttpServletResponse ...................................................... 77
Figure 2.8: Servlet Response Example ................................................ 77
Figure 2.9: Accessing Initialisation Parameters ..................................... 79
Figure 2.10: Bringing it all together................................................... 80
Figure 2.11: Request Dispatching Example........................................... 84
Figure 2.12: Passing and Accessing Request Data ................................... 87
Figure 2.13: Example Tomcat Configuration......................................... 95
Figure 2.14: Example of a WAR File................................................... 97
Figure 2.15: Example Application Configuration .................................... 98
Figure 3.1: Interaction Between a Servlet and a JSP ..............................105
Figure 3.2: Translation and output of a simple JSP................................107
Figure 3.3: Simplified View of the Generated Servlet Code ......................109
Figure 3.4: Produce Code..............................................................111
Figure 3.5: Code in a JSP ..............................................................113
Figure 3.6: Generated Java Code.....................................................113
Figure 3.7: Use of Declarations in JSP ...............................................114
Figure 3.8: Use of Directives on a Page .............................................117
Figure 3.9: Example of Include Directive............................................117
Figure 3.10: JSP Page Directive Usage...............................................118
Figure 3.11: Simple Bean Showing Property Gets and Sets .......................121
Figure 3.12: Initializing a bean using an action, with the generated code.....122

Copyright © 2001, DevelopMentor Inc. ix


Guerrilla Java

Figure 3.13: Creating a bean using an action, and the equivalent script block
.......................................................................................125
Figure 3.14: Using jsp:getProperty ...................................................129
Figure 3.15: Setting a Bean Property With a Value ................................129
Figure 3.16: Setting a Bean Property From Request Parameters ................129
Figure 3.17: Initializing a Bean .......................................................130
Figure 3.18: Setting a Bean Property With an Attribute Value...................131
Figure 4.1: Always use PortableRemoteObject.narrow for RMI casts ...........147
Figure 4.2: EJB interposition model..................................................151
Figure 4.3: EJB remote interface.....................................................155
Figure 4.4: EJB home interface (for a stateless session)..........................156
Figure 4.5: Bean class (for a stateless session) .....................................157
Figure 4.6: Local interface defining bean methods................................159
Figure 4.7: Revised remote interface................................................160
Figure 4.8: Revised bean class (for a stateless session) ...........................160
Figure 4.9: Minimal deployment descriptor (for a stateless session)............165
Figure 4.10: Client usage (of a stateless session) ..................................169
Figure 5.1: Type segregation under XML ............................................175
Figure 5.2: The XML Infoset ...........................................................176
Figure 5.3: Traditional DBMS/XML solution .........................................177
Figure 5.4: Just-in-time XML ..........................................................177
Figure 5.5: Post-Schema XML Infoset ................................................180
Figure 5.6: The role of XML Schemas ................................................181
Figure 5.7: Bridging the XML type system ...........................................181
Figure 5.8: ContentHandler Interface ...............................................189
Figure 5.9: DefaultHandler Class .....................................................189
Figure 5.10: Creating and Using a SAX Parser ......................................191
Figure 5.11: Simple Implementation of Content Handler .........................191
Figure 5.12: DOM logical structure example ........................................199
Figure 5.13: DOM Interface Hierarchy ...............................................201
Figure 5.14: DOM Node Interface .....................................................203
Figure 5.15: DOM Document Interface...............................................205
Figure 5.16: Example of DOM in Action..............................................206
Figure 5.17: Location Step Example .................................................213
Figure 5.18: A Location Path ..........................................................214
Figure 6.1: Naming contexts ..........................................................221
Figure 6.2: A directory .................................................................222
Figure 6.3: JNDI architecture .........................................................225
Figure 6.4: JNDI interface/class diagram ...........................................227
Figure 6.5: Obtaining initial context - programmatic properties ................227
Figure 6.6: Obtaining initial context - declarative properties ...................228
Figure 6.7: JDBC driver model ........................................................231
Figure 6.8: JDBC driver types .........................................................232
Figure 6.9: JDBC programming model ...............................................235
Figure 6.10: JDBC driver model.......................................................237
Figure 6.11: JDBC URL .................................................................238

x Copyright © 2001, DevelopMentor Inc.


Guerrilla Java

Figure 6.12: Obtaining a JDBC Connection in the old world (deprecated) .....238
Figure 6.13: Example server DataSource configuration ...........................239
Figure 6.14: Example of how to register a DataSource............................239
Figure 6.15: Obtaining a JDBC Connection in the new world.....................240
Figure 6.16: Obtaining and using a JDBC Statement...............................243
Figure 6.17: Using a JDBC ResultSet .................................................246
Figure 6.18: A simple stored procedure .............................................249
Figure 6.19: Calling a stored procedure passing input parameters..............250
Figure 6.20: Calling a stored procedure harvesting output parameters ........250
Figure 6.21: Handling multiple results...............................................250
Figure 6.22: Using a CachedRowset ..................................................254
Figure 6.23: Using a WebRowset......................................................254
Figure 6.24: Batching techniques.....................................................258
Figure 7.1: Local (single party) transactions........................................271
Figure 7.2: SQL local transactions....................................................271
Figure 7.3: JDBC local transactions ..................................................272
Figure 7.4: Transaction isolation levels .............................................277
Figure 7.5: Setting the transaction timeout ........................................281
Figure 7.6: Simple read-for-update saga ............................................282
Figure 7.7: Shorten code path inside transaction ..................................283
Figure 7.8: Distributed (multi-party) transactions .................................287
Figure 7.9: Using a distributed transaction - the model ..........................288
Figure 7.10: Obtaining a ...............................................................288
Figure 7.11: Using JDBC with a distributed transaction...........................289
Figure 7.12: The problem of coordinating multi-party commit ..................290
Figure 7.13: Ending a distributed transaction - 2 Phase Commit ................290
Figure 8.1: Container uses interception to manage transactions ................297
Figure 8.2: Declarative transaction attributes for a CMT bean ..................303
Figure 8.3: Deployment descriptor for a bean using a container-managed
transaction .........................................................................304
Figure 8.4: Effect of CMT bean declarative attributes on transaction
bracketing/scope (1)..............................................................305
Figure 8.5: Effect of CMT bean declarative attributes on transaction
bracketing/scope (2)..............................................................305
Figure 8.6: The lifetime of a container-managed transaction ...................306
Figure 8.7: Effect of CMT bean declarative attributes on transaction
bracketing/scope (3)..............................................................306
Figure 8.8: Method code for a root CMT bean ......................................307
Figure 8.9: CMT bean dooms transaction - technique 1...........................310
Figure 8.10: CMT bean dooms transaction - technique 2 .........................310
Figure 8.11: Effect of uncaught exceptions : non-root CMT bean in any managed
transaction .........................................................................311
Figure 8.12: Effect of uncaught exceptions : CMT bean outside of a managed
transaction .........................................................................312
Figure 8.13: Effect of uncaught exceptions : root CMT bean in a container-
managed transaction..............................................................312

Copyright © 2001, DevelopMentor Inc. xi


Guerrilla Java

Figure 8.14: Method code for a BMT bean ..........................................316


Figure 8.15: Deployment descriptor for a bean using a bean-managed
transaction .........................................................................316
Figure 8.16: The lifetime of a bean-managed transaction........................317
Figure 8.17: Effect of BMT bean on transaction bracketing/scope (1)..........317
Figure 8.18: Effect of BMT bean on transaction bracketing/scope (2)..........318
Figure 8.19: A client-managed transaction in a Servlet...........................318
Figure 8.20: Effect of caught exceptions : root BMT bean in bean-managed TX
.......................................................................................321
Figure 8.21: Effect of uncaught exceptions : root BMT stateless session bean in
bean-managed TX .................................................................322
Figure 8.22: How CMT stateful session beans discover transaction outcome ..325
Figure 8.23: Lifecycle of a transaction-aware CMT stateful session bean......326
Figure 9.1: Using cookies to manage state..........................................334
Figure 9.2: HttpSession class ..........................................................337
Figure 9.3: Using the HttpSession class..............................................338
Figure 9.4: Using the HttpSessionBindingListener interface......................343
Figure 9.5: Session state held on a single server...................................348
Figure 9.6: Session state held on a single server...................................349
Figure 9.7: The Cookie class ..........................................................351
Figure 9.8: Using Cookies ..............................................................352
Figure 9.9: What data is thread safe in a servlet ..................................355
Figure 9.10: Protecting Application State ...........................................361
Figure 9.11: Protecting Session State ................................................363
Figure 10.1: Lifecycle of a stateless session bean .................................374
Figure 10.2: Lifecycle of a stateful session bean ..................................382
Figure 10.3: Example use of stateful session bean handles ......................385
Figure 11.1: The XML Infoset..........................................................397
Figure 11.2: The post-Schema XML Infoset..........................................398
Figure 11.3: XML Schema syntax......................................................399
Figure 11.4: The role of XML Schemas ...............................................400
Figure 11.5: Bridging the type system ...............................................400
Figure 11.6: Type description and use - Java.......................................401
Figure 11.7: Type description and use - XSD........................................401
Figure 11.8: XML Schema simple types ..............................................403
Figure 11.9: Simple type definition ..................................................404
Figure 11.10: simple type usage ......................................................404
Figure 11.11: Complex type definition ..............................................405
Figure 11.12: Element declarations ..................................................406
Figure 11.13: Defining a derived type by restriction ..............................407
Figure 11.14: Defining a derived type by extension ...............................407
Figure 11.15: Using a type derived by restriction/extension.....................407
Figure 11.16: SOAP framing and extensibility ......................................412
Figure 11.17: SOAP-compliant types .................................................413
Figure 11.18: SOAP-compliant instances ............................................413
Figure 11.19: SOAP method signature ...............................................414

xii Copyright © 2001, DevelopMentor Inc.


Guerrilla Java

Figure 11.20: SOAP method call ......................................................415


Figure 11.21: Making a SOAP method call over HTTP..............................415
Figure 11.22: A SOAP fault ............................................................416
Figure 11.23: WSDL abstract definitions.............................................419
Figure 11.24: WSDL concrete SOAP definitions (part 1)...........................420
Figure 11.25: WSDL concrete SOAP definitions (part ii)...........................420
Figure 11.26: UDDI Pages ..............................................................427
Figure 11.27: UDDI Information Items ...............................................427
Figure 11.28: UDDI Inquiry API ........................................................431
Figure 11.29: UDDI SOAP request/response format................................431
Figure 11.30: UDDI Find Business Example ..........................................431
Figure 11.31: UDDI Find Business Result.............................................432
Figure 11.32: UDDI Find Service Example ...........................................432
Figure 11.33: UDDI Find Service Result ..............................................433
Figure 11.34: UDDI Get Service Detail Example ....................................433
Figure 11.35: UDDI Get Service Detail Result.......................................434
Figure 11.36: UDDI Publishing API ....................................................435
Figure 11.37: UDDI Save Business Example..........................................435
Figure 12.1: Bytecodes are strongly-typed..........................................443
Figure 12.2: Explicit class loading ....................................................447
Figure 12.3: Class Loader Delegation ................................................449
Figure 12.4: JAR Manifest..............................................................453
Figure 12.5: Loading Classes from a Shared Server ................................455
Figure 12.6: Behind the scenes of implicit loading ................................459
Figure 12.7: Explicitly loading an implementation class ..........................461
Figure 12.8: Explicitly loading an implementation class ..........................463
Figure 12.9: Class Loaders Call Back into the VM ..................................467
Figure 13.1: Reflection Object Model................................................475
Figure 13.2: Accessing Fields, Methods, and Constructors........................475
Figure 13.3: Interrogating Fields, Methods, and Constructors ...................476
Figure 13.4: Implementing a Factory ................................................479
Figure 13.5: Using setAccessible......................................................480
Figure 13.6: Intercepting Method Calls with a Proxy ..............................483
Figure 13.7: Creating an Auditor Proxy ..............................................484
Figure 14.1: Entity persistence models ..............................................493
Figure 14.2: Entity concurrency models .............................................494
Figure 14.3: Entity remote interface ................................................497
Figure 14.4: Creating an entity via its home interface............................498
Figure 14.5: Finding an entity via its home interface .............................498
Figure 14.6: Primary key class ........................................................499
Figure 14.7: Instance-less methods in the home interface .......................500
Figure 14.8: Creating, finding, destroying an entity...............................500
Figure 14.9: How the container manages entity bean instances and their
identity..............................................................................504
Figure 14.10: Entity bean class lifecycle ............................................506
Figure 14.11: EJB 1.1 CMP deployment..............................................509

Copyright © 2001, DevelopMentor Inc. xiii


Guerrilla Java

Figure 14.12: EJB 1.1 CMP at runtime ...............................................509


Figure 14.13: Entity bean deployment descriptor for EJB 1.1 CMP..............510
Figure 14.14: Entity bean class for EJB 1.1 CMP ...................................511
Figure 14.15: EJB 2.0 CMP deployment..............................................516
Figure 14.16: EJB 2.0 CMP generated code .........................................517
Figure 14.17: EJB 2.0 CMP at runtime ...............................................518
Figure 14.18: Entity bean class for EJB 2.0 CMP ...................................519
Figure 14.19: Dependent object class for EJB 2.0 CMP ...........................519
Figure 14.20: Entity bean deployment descriptor for EJB 2.0 CMP..............520
Figure 14.21: Entity bean deployment descriptor for EJB 2.0 CMP..............521
Figure 14.22: EJB QL deployment descriptor finder syntax ......................522
Figure 14.23: EJB QL example code..................................................523
Figure 14.24: EJB QL deployment descriptor selector syntax ....................524
Figure 14.25: Entity bean class for BMP .............................................528
Figure 15.1: XSLT Processing ..........................................................543
Figure 15.2: Input and output of an XSLT Processor ...............................544
Figure 15.3: A simple transform--Hello world! .....................................547
Figure 15.4: xsl:value-of example....................................................551
Figure 15.5: Literal Result Elements .................................................552
Figure 15.6: xsl:for-each example....................................................553
Figure 15.7: xsl:sort example .........................................................554
Figure 15.8: xsl:if example ............................................................556
Figure 15.9: xsl:choose example .....................................................557
Figure 15.10: xsl:element and xsl:attribute example .............................558
Figure 15.11: xsl:call-template example ............................................561
Figure 15.12: xsl:with-param example ..............................................562
Figure 15.13: xsl:param example.....................................................562
Figure 15.14: Running a paramaterized transform programmatically...........563
Figure 15.15: xsl:apply-templates example.........................................565
Figure 15.16: irregular input ..........................................................565
Figure 15.17: DTP and irregular input ...............................................566
Figure 15.18: xsl:copy example--identity transform...............................567
Figure 15.19: Consider a different input XML infoset... ..........................569
Figure 15.20: Output escaping for XML output .....................................570
Figure 15.21: Output escaping for text output .....................................570
Figure 15.22: Whitespace-only nodes in the input XML infoset ..................571
Figure 16.1: The SecurityManager Intercepts Calls to Protected Resources ...577
Figure 16.2: Turning on the SecurityManager.......................................577
Figure 16.3: Checking All Classes on the Stack .....................................579
Figure 16.4: Setting and Retrieving the CodeSource ..............................579
Figure 16.5: Sample Policy File .......................................................581
Figure 16.6: From the Policy File to the AccessController........................582
Figure 16.7: Choosing the Policy from the Command Line .......................585
Figure 16.8: Wildcards in the Standard Permissions ...............................587
Figure 16.9: Defining a Custom Permission .........................................588
Figure 16.10: Using a PrivilegedAction ..............................................591

xiv Copyright © 2001, DevelopMentor Inc.


Guerrilla Java

Figure 17.1: A client HTTP request...................................................599


Figure 17.2: The server challenge for Basic Authentication......................599
Figure 17.3: The client resubmits the HTTP request with Basic Authentication
credentials..........................................................................599
Figure 17.4: The server challenge for Digest Authentication.....................600
Figure 17.5: The client resubmits the HTTP request with Digest Authentication
credentials..........................................................................601
Figure 17.6: The server challenge for either Basic or Digest Authentication ..602
Figure 17.7: 4-way SSL handshake....................................................607
Figure 17.8: Programming SSL on the client ........................................609
Figure 17.9: Servlet container uses web application descriptor to make security
decisions ............................................................................613
Figure 17.10: Configuring a minimal security constraint to trigger
authentication .....................................................................615
Figure 17.11: Configuring application-wide authentication for security-
constrained resources.............................................................616
Figure 17.12: Form-based authentication configuration ..........................616
Figure 17.13: Form-based authentication pages ...................................617
Figure 17.14: Configuring data integrity/privacy level between caller and
server................................................................................619
Figure 17.15: Configuring roles .......................................................621
Figure 17.16: Configuring role authorization .......................................622
Figure 17.17: Configuring resource authentication ................................623
Figure 17.18: Programmatic security in a Servlet..................................625
Figure 17.19: Configuring role references...........................................626
Figure 17.20: A simple hash class ....................................................627
Figure 17.21: Client use of the hash class...........................................627
Figure 17.22: Servlet use of the hash class .........................................628
Figure 17.23: Authenticating to an EJB server .....................................631
Figure 18.1: A JSP containing tags ...................................................637
Figure 18.2: A JSP containing tags ...................................................641
Figure 18.3: Tag interface and TagSupport class...................................643
Figure 18.4: Example of Coding and using a Simple ...............................645
Figure 18.5: Example of a Deployment Descriptor.................................646
Figure 18.6: Flow of Control for a Simple Tag......................................647
Figure 18.7: Iteration Tag Interface .................................................649
Figure 18.8: Example of Iteration Tag Code. .......................................649
Figure 18.9: Iteration Tag Flow .......................................................650
Figure 18.10: Body interface and BodyTagSupport class ..........................653
Figure 18.11: The BodyContent class ................................................654
Figure 18.12: Example of ..............................................................654
Figure 18.13: Example of a Body tag.................................................655
Figure 18.14: Flow of Control for a Body Tag.......................................656
Figure 18.15: Example of Body Tag showing the usage and the generated code.
.......................................................................................656

Copyright © 2001, DevelopMentor Inc. xv


Guerrilla Java

Figure 18.16: Example of Nested Tag showing the usage and the generated
code. ................................................................................660
Figure 18.17: Example of a Tag Creating an Object to Script....................667
Figure 18.18: Example of Defining a Script Variable Created by a Tag .........668
Figure 18.19: Example of Defining the scope of a Script Variable Created by a
Tag...................................................................................668
Figure 18.20: Specifying when a script variable is available .....................669
Figure 19.1: Remote Procedure Call model .........................................675
Figure 19.2: Anatomy of a message ..................................................679
Figure 19.3: Point-to-point messaging ...............................................680
Figure 19.4: Publish-and-subscribe messaging......................................681
Figure 19.5: JMS object model........................................................687
Figure 19.6: Setting up to send/receive ptp messages............................689
Figure 19.7: JMS message headers ...................................................691
Figure 19.8: Sending ptp messages with different bodies ........................692
Figure 19.9: Receiving ptp messages synchronously ...............................693
Figure 19.10: Receiving ptp messages asynchronously ............................694
Figure 19.11: Message selector .......................................................696
Figure 19.12: Return-address style delivery ........................................696
Figure 19.13: Simple synchronous return-address style delivery ................697
Figure 19.14: Sending ptp messages under a local TX.............................699
Figure 19.15: EJB interposition model for message-driven bean ................703
Figure 19.16: Bean class for a message driven bean...............................705
Figure 19.17: Deployment descriptor for a message driven bean ...............706
Figure 19.18: Lifecycle of a message-driven bean .................................707
Figure 20.1: Application Listener.....................................................725
Figure 20.2: Configuring A Listener in the Deployment Descriptor..............726
Figure 20.3: Code Path to Servlet through filters ..................................729
Figure 20.4: ..............................................................................731
Figure 20.5: ..............................................................................732
Figure 20.6: Creating a Request Wrapper ...........................................735
Figure 20.7: Example Filter Configuration ..........................................737

xvi Copyright © 2001, DevelopMentor Inc.


Module 1

HTTP

Copyright © 2001, DevelopMentor Inc. 17


After completing this module, you should be able to:
 explain the request/response natures of HTTP
 understand HTTP headers and how they are used
 understand the structure of an HTTP request/response
 understand how content is delivered in HTTP (Content-Length and
Content-Type)
 understand the difference between GET and POST

18 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP Basics
HTTP is a relatively simple Request/Response
protocol. It is ubiquitous across platforms and
languages and passes easily through firewalls

Copyright © 2001, DevelopMentor Inc. 19


Module 1: HTTP

Using HTTP As RPC


HTTP==RPC

• HTTP is a highly stylized RPC protocol


• Simple request/response framing over TCP
• Ubiquitous cross-platform/language support
• Highly scalable server-side plumbing is ubiquitous
• Extensible and flexible protocol
• Typically the only thing allowed over firewalls

20 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

This chapter is going to look at HTTP with a view to it being used in a business-
to-business environment, which means viewing HTTP as a way of making RPCs.
Why is HTTP so important? Our world view is that your clients will be
external to your network. How will these clients access your services, i.e.
which protocol will they use? Many protocols are available, notably RMI/JRMP,
RMI/IIOP and DCOM, but each of these has the same set of problems. They
don't scale well (into the hundred's of thousands of connections) and they
typically will not be allowed over your firewalls. HTTP self evidently does
scale, and is about the only protocol that will be allowed over a firewall, so
typically, will be the protocol of choice.
HTTP is also truly ubiquitous. HTTP servers and clients are available on every
platform, and certainly the platforms we care about (the various flavours of
Unix and Windows). HTTP is also easy to program in many languages. At the
simplest level writing an HTTP server and client is no more than socket
programming.
The HTTP specification (RFC 2616) allows all parts of the protocol to be
extended, provided that both parties involved in the conversation understand
the extensions.
As we said this chapter will focus on using HTTP as an RPC mechanism. As
figure 1.1 shows, an RPC call has 4 parts: the What - what is it we want to
achieve; the Who, who are we trying to call; the Input parameters; and the
Output parameters. At first glance, it may not seem that HTTP has these four
parts, but as we go through this chapter we will see how the RPC concepts fit
into the HTTP model.

Who? Input

stock = server.GetPreferredStock("MSFT", "SUNW");

What?
Output
Figure 1.1: RPC

Copyright © 2001, DevelopMentor Inc. 21


Module 1: HTTP

Using HTTP
HTTP Basics

• User-Agent establishes TCP connection to Server


• Typically over port 80
• User-Agent sends HTTP request message to Server
• Server processes request and sends back HTTP response message
• TCP connection recycled for next transaction unless explicitly closed by
either party

22 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

In HTTP the client is called the 'User-Agent." The user-agent is the thing that
starts an HTTP conversation. Remember that HTTP is a request response
protocol, i.e. it does not support asynchronous or "push" processing, something
has to send a request to the server to start a conversation. That something is
the user-agent.
Although they could listen on any port, HTTP servers typically "listen" on
port 80. So for a client to establish a link to an HTTP server, the client tries to
connect to that port. Once that TCP connection has been established, the
client sends an HTTP request to the server (we will see what a request looks
like in a moment). The request could be for a static resource (such as an HTML
page) or it could be a request for the server to execute some code on behalf of
the client (a servlet maybe). The server will process the request, and send a
response message back to the client.
In the interests of scalability, HTTP conversations want to be as short as
possible, so the HTTP connection should be closed as soon as possible.
However, to deal with the scenario where a client wants to make multiple
requests to the server in a very short period, a server and client can keep the
connection open (think of the scenario where a client downloads a page, then
wants to get all the images on that page, the client doesn't want to have to
keep opening and closing the connection). Because of this an HTTP connection
is typically kept open until either the client or server explicitly closes it, or the
server times out.

Copyright © 2001, DevelopMentor Inc. 23


Module 1: HTTP

HTTP Endpoints
The Who

• HTTP endpoints are called "resources" that are identified by Uniform


Resource Locators
• Uniform Resource Locators contain "hints" to find the resource
• HTTP URLs consist of a host, port, and absolute path
• HTTP URLs can consist of only a relative path interpreted in some context

24 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP endpoints are called resources. Clients access these resources by sending
an HTTP request. Resources are identified by Uniform Resource Locators
(URLs), shown in figure 1.2. The various parts of the URL are labeled.

Host Absolute Path

http://betty.develop.com:8080/object/four

Protocol Port

Relative Path

../five/childof5

Figure 1.2: HTTP Endpoints

A URL consists of
A protocol. This identifies the protocol the server and client will use to
communicate AND the port the server will be listening on (unless overridden
elsewhere in the URL).
A host name. This will be resolved to the address of the server that the
client connects to.
An optional port. The protocol part of the URL also identifies the port on
which the server will listen by default. If the server is listening on a different
port, it can be specified here.
And finally a path. The path is meaningful to the server. It identifies a
resource on the server and only the server understands how to translate the
path into something sensible.
URLs can also contain query strings, as figure 1.3 shows. A query string
contains extra data that's meaningful to the resource being requested. This
data is in the form of name: value pairs.

Copyright © 2001, DevelopMentor Inc. 25


Module 1: HTTP

http://betty.develop.com:8080/object?x=3&y=Tim+Doe

Query String
Figure 1.3: HTTP URL with Query String

A query string starts with a ? and each "name=value" pair is separated by an &
Beware that some servers will limit the amount of data that can be present in a
query string, often to 256 or 512 characters, and if you exceed this limit will
return a "414 Request-URI Too Long" response
Not all characters are valid in a URL. For example a URL containing a space
character would not be valid. Because of this clients must "encode" a URL
before sending it to a server, and the server "decodes" the URL before
presenting it to the requested resource. Browsers and web-servers do this
automatically, but if you are writing your own client, you will need to do this
yourself.
Most illegal characters in a URL are escaped as hexadecimal pairs, so for
example:
"this isn't a legal string" encodes as this (where the quotes are not part of
the string)
"this+isn%27t+a+legal+string"
Notice that a space encodes as a "+" and other symbols encode as %xx (so '
encodes as %27)
By the way, doing this in Java code is relatively easy, call
java.net.URLEncoder.encode("some string");

26 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP Messages
Request and Response consists of three components

• A mandatory Request-Line or Status-Line (text)


• A set of headers (text)
• An optional message body (tagged stream of bytes)
• Headers are CRLF-delimited Name: Value pairs (delimited by a blank line)
• Accept and Content-Type headers define MIME type of body
• (optional) Content-Length header specifies size of body

28 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

An HTTP message consists of a request message and a response message. A


request starts with a request line and a response with a response line. Both
requests and responses have headers and both may have a body. All lines are
carriage-return/line-feed delimited. Figure 1.4 shows this.

Body Headers Request-Line

Status-Line Headers Body

Figure 1.4: Request/Response Pair

The opening line of an HTTP request/response is request line/status line, which


we discuss in a moment. Following that are zero or more headers and an
optional body. If headers are present (and the only mandatory header is the
"Host:" header in HTTP 1.1) they are CRLF delimited name/value pairs. The
HTTP specification groups headers together but they all follow the same
syntax, Name: Value. Among the most important headers are the Content-
Type and Content-Length headers. These headers signal the data type of the
body and how large that body is (if there is a body of course) Figure 1.5 shows
this.

Format/Length <request or status line>


of Body <other headers>
Content-Length: 12
Content-Type: text/plain
Message Body
Hello, World

Figure 1.5: HTTP Headers and Body

The headers will always be followed by a blank line. This signals to the client
or server that the headers have finished and the body is about to begin. If
there is a body, the headers will contain a content-type header to signify the
type of data the body contains--this will be a MIME type. Both an HTTP request
and response can have a body. An HTTP request will typically have a body if it's
a POST request, whereas most HTTP responses will have a body.
As well as specifying a MIME type if they send a body, user-agents can also
specify the data types they are willing to accept. They do this by specifying an
Accept header or headers. An Accept header can contain comma separated set
of mime types, and a single request can contain multiple Accept headers. More

Copyright © 2001, DevelopMentor Inc. 29


Module 1: HTTP

highly qualified types are preferred over less qualified types. So, text/xml is
preferred over text/* is preferred over */*

30 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP Requests
HTTP requests always begin with a request line

• Method: HTTP operation to perform


• Request-URI: absolute path/URI for target resource
• HTTP-Version: HTTP/1.0 or HTTP/1.1
• HTTP supports seven built-in methods
• GET and POST most common
• GET processing must be idempotent
• Only POST requests can contain a message body

32 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP requests always start with a request line. Request lines have a standard
format as shown in figure 1.6. The request line always starts with an HTTP
method, followed by the request URI, and then finally the HTTP version.

Request-Line
GET /object/four HTTP/1.1
Headers go here

Figure 1.6: HTTP Request

The HTTP version will be one of 0.9, 1.0 or 1.1 (it's unlikely you will see HTTP
0.9 used today). HTTP 1.1 is (obviously) the most recent version, changes from
HTTP 1.0 -> HTTP 1.1 include: extra methods; better proxy support; and a
different connection model (1.1 keeps connections alive by default 1.0 closes
them).
The HTTP method is typically one of the standard seven methods (but this is
extensible), and we'll cover these in a moment.
The request URI identifies the resource on which to apply the request. The
URI can take several forms: it could be a relative URI, an absolute URI, "*" or an
authority. Relative URIs are the usual form used (as shown in figure 1.6),
absolute URIs are required when the request is being made through a proxy. All
HTTP 1.1 servers have to accept absolute as well as relative URIs. The other
two forms are "*" for requests that effect the server directly (such as the
OPTIONS methods) and an "authority" for the reserved "CONNECT" method.
HTTP supports seven pre-defined, plus one reserved method. The seven pre-
defined methods are GET, POST, PUT, OPTIONS, TRACE, DELETE and HEAD, and
the reserved method is CONNECT. The specification also allows for extra
methods to be defined. The specification defines GET and HEAD as "safe"
methods, that is methods that do nothing other than a retrieval. Further to this
GET, HEAD, PUT and DELETE, OPTIONS and TRACE are defined as idempotent;
that is running the method more than once has exactly the same effect as
running the method once
POST is different however. POST is not defined to be IDEMPOTENT, so
running POST more than once may not have the same outcome as running POST
once.
Figure 1.7 shows an example of a GET, while figure 1.8 shows a POST. These
are the two most important methods, and the ones we will concentrate on.
GET and POST have differences, GET cannot have a body for example, whereas
POST can. The most important difference is, as we've just said, GET should be
idempotent, whereas POST may not be. What this means in practice is that the
client doesn't have to check if the user tries to re-send a GET request.

Copyright © 2001, DevelopMentor Inc. 33


Module 1: HTTP

However, a client shouldn't arbitrarily be allowed to resend a POST--the side-


effects may be disastrous.
GET /object/four?name=Alice HTTP/1.1
Host: betty.develop.com

Figure 1.7: HTTP GET example

POST /object/four HTTP/1.1


Host: betty.develop.com:8080
Content-Length: 12
Content-Type: text/plain

Hello, World
Figure 1.8: HTTP POST example

34 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP Responses
HTTP responses begin with a status line containing a numeric code and
description

• 1xx: Informational--Request received, continuing process


• 2xx: Success--The action was successfully received, understood, and
accepted
• 3xx: Redirection--Further action must be taken in order to complete the
request
• 4xx: User-Agent Error--The request contains bad syntax or cannot be
fulfilled
• 5xx: Server Error--The server failed to fulfill an apparently valid request
• Each Status-Code has an associated String (Reason-Phrase)

36 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

An HTTP Server will take a request from a client and generate a response.
Responses, like requests, consist of a response line, headers and a body. The
response line contains the HTTP version of the server, a response code and a
"reason phrase". The reason phrase is some text that describes the response,
and could be anything, although a recommended set of reason phrases is given
in the specification. Response codes themselves are three digit numbers that
are divided into groups. Each group has a meaning as shown above. We show
some of the most common status code in figure 1.9

HTTP Description Interpretation


100 Continue Request Acknowledged
200 OK Success
303 See Other Redirect to different URL (get)
307 Temp. Redirect Redirect to different URL (repost)
400 Bad Request Malformed Request Msg
401 Unauthorized Access Denied
403 Forbidden Illegal operation request
404 Not Found Unknown resource
405 Bad Method HTTP method not supported
500 Exec Failure Server-side error
501 Not supported Un-recognized HTTP method
Figure 1.9: Common Response Codes

The status code you'll see most often is "200". This means that everything has
succeeded and you have a valid response. The others you are likely to see are
401: you are not authorized to make this request
404: cannot find the requested URI
405: the HTTP method you've tried to execute is not supported by this URL
(e.g. you've sent a POST and the URL will only accept GET)
500: Internal Server Error. You are likely to see this if the resource you are
browsing to (such as a servlet) itself throws an exception

Copyright © 2001, DevelopMentor Inc. 37


Module 1: HTTP

HTTP Redirection
Redirection is a request to the client to retrieve the resources from
elsewhere

• The "300" family of status code allow servers to redirect the user-agent to a
different URL
• Uses "Location" header to provide alternative URL
• 303 redirects to alternative URL using "GET"
• 301/302 older versions of 303 for down-level clients
• 307 redirects to alternative URL using same method

38 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

Sometimes a web application may have to temporarily relocate to another


server (maybe for maintenance reasons). In that case, a web server can be
setup to respond to all requests for a given service with a 307 response. This
says that the resource has temporarily moved and the "Location" header
identifies the new location.
There are going to be other occasions when a web-based application cannot
respond to a request until some pre-requisite is satisfied, for example, user
may have to logon before accessing a certain page. This means that when a
request comes in to a web application, the application has to check if the user
has logged on, and if not, send the user to the logon page. One way of doing
this is an HTTP redirect.
An HTTP redirect is a response from the server to the client that the client
should retrieve either another resource or maybe just change the HTTP
method. In the logon example, if a user sends a request to
http://someserver/somepage.html, if the user isn't logged on the server will
send a redirect response, redirecting the client to
http://someserver/logon.html (say). The redirect would be a 303 response
with a Location header of Location: http://someserver/logon.html
A 303 status is logically different to a 307 status. 307 says, redirect to
Location: and use whatever HTTP method you used to come here, whereas 303
says, redirect to Location: and use GET as the method regardless of the verb
you used to come here. A 303 response says, "I can't satisfy the request here,
but if you go to the Location I've specified there will be something there to
help you, and you must send a GET to that location". This covers the above
case where the client may have sent a POST, but has to logon first and the
logon page is only available via a GET.
Figure 1.10 shows a couple of re-direction examples. Beware that
redirection has a major downside; it involves an extra round-trip from client to
server to satisfy the request (and round-trips are evil). Servlets offer another
way to achieve a similar outcome (called Request Dispatching) that we will look
at later.

Client will “GET” HTTP/1.1 303 See Other


this URL Location: http://helen.com/ep

Client will resubmit HTTP/1.1 307 Temporary Redirect


to this URL Location: http://helen.com/ep

Figure 1.10: 303 and 307 Response Codes

Copyright © 2001, DevelopMentor Inc. 39


Module 1: HTTP

More HTTP
There are several differences between HTTP/1.0
and HTTP/1.1. We look at the differences in
connection management and we also look briefly at
how HTTP also offers limited support for security
and connection management.

Copyright © 2001, DevelopMentor Inc. 41


Module 1: HTTP

HTTP Connections
HTTP 1.0 and HTTP 1.1 manage connection lifetimes differently

• HTTP/1.0 defaulted to short-lived TCP connections


• Connection per request/response
• Termination of TCP connection indicated end of body
• Connection: Keep-Alive header defeats connection termination
• HTTP/1.1 defaults to long-lived TCP connections
• Either side free to drop connection
• May use Content-Length to indicate end of body
• May use chunked encoding to transfer body in chunks
• Connection: close header indicates connection termination

42 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

One of the differences between HTTP 1.0 and HTTP 1.1 is the management of
connection lifetimes. In HTTP 1.0, a connection would (by default) last for a
single request/response pair. A client would request a page, get the page, and
the connection would close. The client would then parse the page and find an
<IMG> tag, it would open a new connection, retrieve the image and close the
connection. The client would carry on parsing the page, find another <IMG> tag
and.... you get the picture. To get around this, in HTTP 1.0 a client could send
a Connection: Keep-Alive header, requesting that the server not terminate the
connection after the end of the response. To terminate the connection one
side would then send a Connection: close header.
In HTTP 1.1 things connections are managed differently in that they are
kept-alive by default. The connection is only closed when one side sends a
Connection: close header.
When transferring data using HTTP it is (obviously) important for the
receiver to know how much data it is expected to consume. In HTTP 1.1 there
are various options for specifying the size of the body. A server or client can
set the Content-Length header. This specifies the size of the content in octets.
A server can also specify a "Transfer-Encoding: chunked" header. This tells the
client that data will be sent back in chunks, with the data being preceded by
the chunk size in hexadecimal.
The data looks like this
Transfer-Encoding: chunked

9
PhoneBook
6
Entry:
0

Copyright © 2001, DevelopMentor Inc. 43


Module 1: HTTP

HTTP Session Management


HTTP is a stateless protocol

• Managing conversation state in HTTP requires work


• Few (if any) web servers expose the correlation between connections and
requests
• Some "key" must be passed back and forth to identify logical client/server
session
• A: Server can encode key in a URL for next request
• B: Server can encode key in content body
• C: Server can encode key in HTTP cookie
• C is the cleanest
• C is least resilient to paranoid users or hand-rolled HTTP stacks

44 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP is stateless. What does this mean? It means that by default no


conversational state is kept, i.e. when a client makes a request, the server has
no way of identifying the client, and no way of knowing if this is the client's
first request or one in a series of requests that the client has made.
There are many ways to create conversational state in HTTP. You basically
need to send some extra data on each request/response pair that uniquely
identifies the client. The client would save the value of the header somewhere,
so that when it made a request to the same server it would pass back that
value. The server would maintain a connection between this value and some
conversational state. This value could be sent as an extra header, it could be
sent in the body of the request/response, it could be added to the query string
or it could be encoded into the URL the client is requesting.
The most common approach is passing the data in an extra header, the data
is called a cookie and the headers are Cookie (which goes from client to server)
and Set-Cookie (which goes from server to client). We will be discussing these
in detail later.

Copyright © 2001, DevelopMentor Inc. 45


Module 1: HTTP

HTTP Security
HTTP has little support for security

• HTTP supports Secure Sockets Layer (SSL) as a transport (a.k.a. HTTPS)


• SSL seals the channel against prying eyes
• SSL defaults to server-side authentication using certificates
• SSL can authenticate client-side certificates
• Many applications use alternative client-authentication techniques
• UID/PWD table in database or directory service
• External authentication authorities (e.g., Microsoft Passport)

46 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

HTTP has little built-in support for security. The specification basically punts
and says to look at RFC2617. There are techniques you can use for
authentication and encryption, the most notable of which is SSL (for sealing the
channel), and we will look at these in detail later.

Copyright © 2001, DevelopMentor Inc. 47


Module 1: HTTP

Client Code
Java supplies many support classes for writing HTTP
client code. This module examines the java.net.*
classes needed to do this.

Copyright © 2001, DevelopMentor Inc. 49


Module 1: HTTP

java.net.URL
Encapsulates a URL

• URL(String protocol, String host, int port, String file)


• URL(String spec)
• Call url.openConnection() ...
• ...examines protocol and returns a java.net.URLConnection

50 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

The java.net packages supply many of the things that are required to do both
server and client side network programming with Java. In particular the
java.net package contains a Socket and a ServerSocket class. To create
an HTTP client then, one could simply open a Socket and start sending HTTP.
Of course a lot of this code would be exactly the same across clients, i.e.
setting the request line and setting the headers. Because of this the java.net
package contains helper class to handle different protocols and to handle URLs
The first helper class is java.net.URL, this allows you to connect to a
server in a protocol independent manner. You create a URL by passing it the
protocol you want to use (http, ftp, etc), the server to connect to, the port to
use, and so on. You can pass these parameters either as a URL or separately.
Once the URL is created you can use it to connect to and read data from the
server, using the protocol specified at creation time.
java.net.URL objects don't themselves understand each protocol. For
example, a java.net.URLobject doesn't understand how to talk HTTP,
instead that is left to a 'protocol handler'. The URL object examines the name
of the protocol passed in and uses that to create an instance of the correct
protocol handler. In our case the URL object will create a protocol handler that
understands HTTP. To manipulate the HTTP stream directly (i.e. to set headers
or send data) we need to access the protocol handler the URL object has
created. We do this by calling url.openConnection. This returns a
URLConnection object typed to the right protocol (so in our case a
HttpURLConnection object). Note that a connection hasn't been established
yet - just the ability to make the connection.

Copyright © 2001, DevelopMentor Inc. 51


Module 1: HTTP

java.net.URLConnection and friends


Send/Receive data after establishing connection

• URLConnection is abstract
• Actually use a subclassed URLConnection of the 'correct' type
• HttpURLConnection in this case
• Returned xxxURLConnection will have generic and protocol specific
methods
• Use URLConnection to send/receive data

52 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

The HttpURLConnection allows us to manipulate the HTTP request and to


harvest the response. HttpURLConnection allows us to do things such as
specify the HTTP method to use, to set headers, to access the input stream and
to access the output stream.
There are several things to be aware of when using this class; to set a
header call setRequestProperty, if you are going to send data you have to
let the connection know by calling setDoOutput(true);, the connection is
made by calling connect, and finally, if anything goes wrong in the HTTP
conversation, the HttpURLConnection object ALWAYS throws a
java.io.FileNotFoundException! Figure 1.11 shows an example of doing
an HTTP GET and figure 1.12 shows how to do a POST.
URL url = new URL("http://server/myEndPoint");

HttpURLConnection con =
(HttpURLConnection)url.openConnection();
con.setRequestMethod("GET");

con.connect();

InputStreamReader ins = new


InputStreamReader(con.getInputStream());
BufferedReader bufReader = new BufferedReader(ins);
String strOutput = null;

do
{
strOutput = bufReader.readLine();
if (strOutput != null)
System.out.println(strOutput);
}while (strOutput != null);
Figure 1.11: Simple Client GET

Copyright © 2001, DevelopMentor Inc. 53


Module 1: HTTP

String strOut = readDataToPOST();

URL url = new URL("http://server/soapServer");


HttpURLConnection con =
(HttpURLConnection)url.openConnection();

con.setRequestProperty("Content-Type", "text/xml");

con.setRequestMethod("POST");
con.setDoOutput(true);

OutputStreamWriter writer = new


OutputStreamWriter(con.getOutputStream());
writer.write(strOut);
writer.flush();

con.connect();

// as doGet to read the data


Figure 1.12: Simple Client POST

54 Copyright © 2001, DevelopMentor Inc.


Module 1: HTTP

Summary
• HTTP is a request/response protocol
• HTTP POST is for application requests
• HTTP GET is for browse-only applications
• HTTP messages have headers and an optional body
• HTTP headers are text-based
• HTTP body is an arbitrary MIME-tagged byte stream

Copyright © 2001, DevelopMentor Inc. 55


Module 2

Servlets I

Copyright © 2001, DevelopMentor Inc. 57


After completing this module, you should be able to:
 explain the architecture of servlets
 understand how to write a servlet
 explain how to dispatch requests to other servlets
 understand how web application deployment works

58 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Servlets Introduction
Servlets are server-side Java code that execute in
response to an HTTP request. They typically act as
the 'controllers' in the MVC model and are able to
call other servlets.

Copyright © 2001, DevelopMentor Inc. 59


Module 2: Servlets i

Servlets
Servlets

• Are server-side Java code that is run in response to a client request


• Run in containers that implement HTTP
• Must implement javax.servlet.Servlet
• Receive HTTP requests as an HttpServletRequest
• Send response to "client" through a HttpServletResponse

60 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

When building server applications it is good to be able to take advantage of the


infrastructure offered by the server. So when building a web-based application,
it shouldn't be necessary to build a new HTTP server for each application.
Servers are typically designed to be extensible: historically, this extension was
done by using CGI and Perl. In the Microsoft world, extension is done using
IISAPI extensions and filters, with ASP just being a (very complex) IISAPI
extension. Sun realised that a similar mechanism was needed for Java if Java
was ever to be an option in building web-based applications. Servlets fill this
need.
Servlets are Java components that execute in some container; typically that
container is an HTTP server, but it doesn't have to be. Servlets are designed to
be generic but at the moment only HTTP servlets are officially supported and
we will be concentrating on them.
The servlet specification outlines an application programming model that
containers should adhere to, which will be discussed throughout the course.
The main points to note at the moment are that servlets execute as part of an
application, and are able to communicate to other resources in the application
via a shared object. This object is of type javax.servlet.ServletContext
The container effectively hides the serialization details of HTTP from a
servlet, that is, a servlet doesn't need to be able to parse each incoming
request line to make sense of it. Instead a container takes the incoming
request and encapsulates it in a javax.servlet.HttpServletRequest
object. Similarly, the servlet is able to send data back to the client, and
change response headers through a container-created
javax.servlet.HttpServletResponse object.

Copyright © 2001, DevelopMentor Inc. 61


Module 2: Servlets i

Web Applications
Applications are a collection of co-operating resources that share a URL
prefix

• Servlets
• JSPs
• Web pages
• XML/XSLT resources, etc.
• Web server maps incoming URL to a location containing all of the
application's resources
• Most interesting resource is a servlet

62 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

When Servlets execute, they execute as part of a web application. An


application is defined as a co-operating set of resources all accessible via a
common URL. The server is responsible for mapping this URL to the collection
of resources. So for example we may want to create a "books" application, and
have the application available through the books URL (i.e.
http://server/books/someResource.html). The resources could be physically
located anywhere, so long as the server views them as one application. Why is
this important? Well servlets in applications are able to call each other, and
resources in applications can share state.
So what happens when a server receives a request? We show the sequence in
figure 2.1. The server maps the first part of the URL to the application (books
in this case) and the second part of the URL to a resource (bookorder). Here
"bookorder" maps to a servlet (we'll see how to do this in a moment). The
server checks to see if the bookorder servlet is running, if it is the server
retrieves a reference to the servlet. If the servlet isn't running the server will
load it. The server now wants to execute the servlet. All servlets have a
service method that handles requests. The server has to pass to the servlet
all the incoming request information, and harvest the response. To do this the
server creates a javax.servlet.http.HttpServletRequest object and a
javax.servlet.http.HttpServletResponse object, and calls the
service method passing in these objects.

1 3 HttpServletRequest
client Container

4 HttpServletResponse

5 Servlet
public void service{}

1 Client sends an HTTP request


GET /books/bookorder HTTP/1.1
2 Servlet loaded from file system if necessary
3
Container constructs a javax.servlet. http.HttpServletRequest
object
4 Container constructs a javax.servlet. http.HttpServletResponse
object
5 Container calls servlet's service method

Figure 2.1: Servlet Loading

Copyright © 2001, DevelopMentor Inc. 63


Module 2: Servlets i

There are various ways for a container to map an incoming request onto a
servlet. Every web application has a configuration file that servers must
understand, "web.xml". One of the sections of web.xml is servlet configuration.
Figure 2.2 shows that we can give servlets a name, and associate that name
with a class file (which is fully package qualified). Servlets may also have a
mapping, this maps part of the URL to the actual servlet name. In our example
there are two mappings, the first mapping says that any requests to "/DoLogon"
should go to the "Logon" servlet, and that any requests that end in ".lgn" should
also go to the logon servlet. The example HTTP requests show these in action.

GET /books/DoLogon HTTP/1.1


GET /books/Alice.lgn HTTP/1.1
GET /books/servlet/Logon HTTP/1.1
GET /books/servlet/com.develop.Logon HTTP/1.1

<web-app>
<servlet>
<servlet-name>Logon</servlet-name>
<servlet-class>com.develop.Logon</servlet -class>
</servlet>
<servlet-mapping>
<servlet-name>Logon</servlet-name>
<url-pattern>/DoLogon</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Logon</servlet-name>
<url-pattern>*.lgn</url-pattern>
</servlet-mapping>
</web-app>

Figure 2.2: Executing Servlets

Supposing the servlet doesn't have a servlet-mapping. On many servers this


servlet will still be available via a special URL "/servlet". Again, the example
HTTP request shows a client browsing to http://server/servlet/Logon,
this would execute the Logon servlet. And finally, what if the servlet doesn't
have a mapping or a servlet entry in web.xml? It may still be possible to
execute the servlet using the special /servlet URL this time passing the fully
qualified path name of the Java class to the server. Notice that servlets
accessed in this way will not be passed any initialisation parameters (more on
this later).
Note that in figure 2.2, we will now have two servlet instances loaded. One
instance for access to the named servlet (either through /servlet/Logon, or

64 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

through the mappings) and one instance because of the access to the servlet
through its fully qualified class name.

Copyright © 2001, DevelopMentor Inc. 65


Module 2: Servlets i

Writing Servlets
Servlets must implement javax.servlet.Servlet

• init called once when servlet first loaded


• destroy called just prior to termination
• service called for each request to the servlet
• Most of the action takes place in service
• javax.servlet.GenericServlet implements all methods of Servlet
except service
• GenericServlet designed to be sub-classed on a per-protocol basis
• Base servlet development kit only supports HTTP

66 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

All servlets must implement the javax.servlet.Servlet interface. The


interface is shown in figure 2.3. The interface has five methods.
getServletInfo simply returns a string: this string would be a copyright
notice or similar. Each servlet has configuration information associated with it.
For example, it is possible to specify initialisation parameters in web.xml.
These configuration details are available through the servlet's associated
ServletConfig object, and there is one per servlet. The servlet config is reached
by calling getServletConfig
public interface javax.servlet.Servlet
{
public void init(ServletConfig);
public void service(ServletRequest req,
ServletResponse resp);
public void destroy();
public ServletConfig getServletConfig();
public String getServletInfo();
}
Figure 2.3: Servlet Interface

The other three methods determine the servlet's lifecycle. When the servlet is
loaded its init method is called. This method is called once and once only.
This is analogous to the servlet's constructor. It's here that the servlet would
initialise itself: for example, it would use the passed in servlet config to get at
its initialisation parameters.
For every request that this servlet has to process the servlet's service
method gets called. This method will be called many times (once per request),
and will be called concurrently (once per concurrent request), this is where all
the work gets done.
And finally, the destroy method. This gets called when the servlet is
unloaded. In theory the server is free to unload the servlet at any time, in
practice, however, the servlet is likely to be unloaded rarely, if ever, in a
production environment. At development time, it is possible that this method
will get called frequently. Most containers will support the "hot deployment" of
servlets, which means that if the class in memory is older than the class file on
disk, the old version will be thrown away, and the newer version loaded. When
this happens the container will call the servlet's destroy method, reload the
servlet, and call its init method.
Because all of the methods on Servlet, apart from service can be written
in a standard way, Sun provides a base implementation of them in a class
called GenericServlet. Because this class doesn't implement service it is
an abstract class. The implementations of the servlet methods do the right
thing, i.e. init, saves away a reference to the ServletConfig, which
getServletConfig returns. getServletInfo and destroy do nothing.

Copyright © 2001, DevelopMentor Inc. 67


Module 2: Servlets i

The service method is not implemented in this class, in fact, how could it be?
The service method has to do two things. It has to be aware of the specifics of
the protocol used to execute this servlet, and it has to execute business logic.
A generic class can do neither of these things
Because of this, GenericServlet is designed to be extended on a per-
protocol basis. The Servlet API from sun comes with support for only one
protocol, HTTP. In theory, other protocols could have been supported (POP3,
SMTP maybe), but none, officially, have been, and none are likely to be in the
foreseeable future.

68 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Writing a Servlet
HTTP Servlet

• HttpServlet extends GenericServlet


• Provides service(ServletRequest req, ServletResponse resp)
• Which calls service(HttpServletRequest req,
HttpServletResponse resp)
• This calls a helper method based on the verb
• The servlet services the request...
• ... and sends the result back to the client
• As an HTTP response

70 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

As we said above, the Servlet API comes with support for the HTTP protocol.
This is in the form of the HttpServlet class. This class extends generic
servlet and implements the service method. Remember the service method
has two logical tasks: to understand the protocol and to carry out the business
logic. The service method implemented by HttpServlet obviously can't
perform your business logic, but it does understand HTTP.
When the servlet container calls the servlet's service method, it first
creates HttpServletRequest and HttpServletResponse objects. It then
calls service. But service takes a ServletRequest and a
ServletResponse, so HttpServlet's implementation of service simply casts
the request and response parameters to be the right type and calls the helper
service method. This is shown in figure 2.4.
public void service(ServletRequest req, ServletResponse resp){
service ((HttpServletRequest) req, (HttpServletResponse)resp)
}

public void service(HttpServletRequest req,


HttpServletResponse resp){
String str = req.getMethod();
if(str.equals("GET"))
doGet(req, resp);
else if(str.equals("POST")
doPost(req, resp);
etc.
}

public void doGet(HttpServletRequest req,


HttpServletResponse resp){}
public void doPost(HttpServletRequest req,
HttpServletResponse resp){}
public void doPut(HttpServletRequest req,
HttpServletResponse resp){}
Etc…

Figure 2.4: HTTP Servlet Code

This figure also shows how the helper service method deals with the request.
It looks in the HttpServletRequest object for the HTTP verb used, and calls
a helper method based on that verb. So if the HTTP request was a "GET" doGet
is called. It is our responsibility to implement this helper.
Our servlet will typically extend HttpServlet and provide a doGet method
(as shown in figure 2.5), or a doPost method. It is here that all the work is
done!

Copyright © 2001, DevelopMentor Inc. 71


Module 2: Servlets i

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class MyServlet extends HttpServlet


{
public void doGet(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException
{
// see rest of course...
}
}
Figure 2.5: Our Servlet Code

72 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

HTTP Request Processing


HttpServletRequest provides access to HTTP request

• Headers
• Query string
• Session information
• Etc.

74 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

The container calls the servlet passing in an HttpServletRequest and a


HttpServletResponse object. The HttpServletRequest object contains
the data that was passed in the HTTP request. This data contains (but is not
limited to) the HTTP request headers, any SSL information, and any query
string. The query string would have been parsed by the container and is made
available to the servlet as a set of name value pairs. As can be seen from figure
2.6 access to the HTTP information is through methods of the
HttpServletRequest object. For example, the headers are available
individually through getHeader, or as an enumeration through getHeaders.
GET /servlet/MyServlet?uname=foo&pword=bar
Host: foo.develop.com

public void doGet(HttpServletRequest req,


HttpServletResponse resp)
{
String strHost = req.getHeader("Host");
String strName = req.getParameter("uname");
String strPwd = req.getParameter("pword");
// etc...
Figure 2.6: Request Processing

There are various ways to access the "user" data in the request (i.e. the query
string, or the body if the request is a POST). You can access the query string as
a single entity by calling getQueryString. You can access the entities that
make up the query string (the name=value pairs) by calling getParameter.
You can get an enumeration of all the parameter names by calling
getParameterNames, and if a parameter possibly has multiple values you can
call getParameterValues to retrieve all the values. And finally, if you are
running in a servlet 2.3 container, you could call getParameterMap to
retrieve a java.util.Map containing the name/value pairs.
If the HTTP request is a POST, the POST body will be treated like a query
string and parsed only if the "Content-Type" header is application/x-www-
form-urlencoded, if the content type is different to this the body is
available by calling request.getInputStream()

Copyright © 2001, DevelopMentor Inc. 75


Module 2: Servlets i

Response Processing
HttpServletResponse

• Provides Access to HTTP Response


• Set the status code
• Set response headers
• Set the response body

76 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

As figure 2.7 shows, the HttpServletResponse object gives us access to the


HTTP response message. Using this class we can set the response code, redirect
the request, or simply return data to the client. To return data as part of the
response, the servlet has two options: send back text data; or send back binary
data. To send back binary data the HttpServletResponse object gives the
servlet access to a ServletOutputStream through the getOutputStream
method. To send back text data, the servlet uses a PrintWriter accessible
through the getWriter method. Note that this PrintWriter may be
unbuffered, which means that as soon as the servlet writes to the
PrintWriter any response headers that have been set will be flushed to the
client. Before writing any data back the servlet should set the content-type of
the response. Figure 2.8 shows this in action.
public void sendRedirect(String location){}
public void sendError(int sc, String name){}
public void setStatus(int sc){}
public ServletOutputStream getOutputStream(){}
public PrintWriter getWriter(){}
public void setContentLength(int len){}
public void setContentType(String type){}
public void resetBuffer(){}
public void setBufferSize(int size){}
Figure 2.7: HttpServletResponse

public void doGet(HttpServletRequest req,


HttpServletResponse resp)
throws IOException, ServletException {
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
out.write("SomeServlet Response");
}
Figure 2.8: Servlet Response Example

Copyright © 2001, DevelopMentor Inc. 77


Module 2: Servlets i

Helper Classes and Interfaces


Helper Classes

• ServletConfig
• Gives access to servlet's initialization parameters
• ServletContext
• Can store application wide data
• Can log messages
• Forward calls to other resources

78 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Servlets also come with a whole set of helper classes. Two of the important
ones are the ServletConfig and ServletContext class. Each web
application has a single ServletContext instance (in fact it is a single
instance per Java VM) available to all resources in that application. The
ServletContext can be used to share data between resources, and to allow
one resource to execute another (i.e. one servlet can call another). We'll cover
both of these features in more detail later.
While the ServletContext is an application singleton, each servlet has its
own associated ServletConfig object. The ServletConfig gives the
servlet access to its configuration information, the most important part of
which is its initialisation parameters. We saw earlier that servlets can be
configured in the applications deployment descriptor, they can be named.
Named servlets can have a <init-param> section that allows the deployer to
specify "start-up" values for the servlet. These are made available to the
servlet through the ServletConfig object, which has a getParameter
method. Figure 2.9 shows how to access the values.
public void init(){
// In 'named' servlet only
String url = getServletConfig().getParameter("url");
}

<web-app>
<servlet>
<servlet-name>Logon</servlet-name>
<servlet-class>com.develop.timereports.Logon</servlet-class>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:odbc:Football</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Logon</servlet-name>
<url-pattern>/Logon</url-pattern>
</servlet-mapping>
</web-app>

Figure 2.9: Accessing Initialisation Parameters

So where are we? Figure 2.10 shows the hierarchy of a servlet. The base class
(GenericServlet) implements the javax.servlet.Servlet interface and
the javax.servlet.ServletConfig interface (i.e. the servlet and the
configuration object are one and the same). HttpServlet extends servlet,
and finally our class extends HttpServlet.

Copyright © 2001, DevelopMentor Inc. 79


Module 2: Servlets i

Gives access to initialisation


params and ServletContext
init, destroy, service
ServletConfig Servlet

Abstract class – doesn’t


implement service()

GenericServlet
Concrete class – service
method calls
appropriate helper

HttpServlet
ServletContext
Implements
doXXX()

MyServlet
Figure 2.10: Bringing it all together

80 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Request Dispatching From Servlets


Servlets often work as the controller in the "Model,
View, Controller" architecture. The controller
servlet will create a Java Bean (the model), and
then pass control to a JSP (the view) by using
request dispatching.

Copyright © 2001, DevelopMentor Inc. 81


Module 2: Servlets i

Request Dispatching
One servlet can call another

• ServletContext.getRequestDispatcher()
• Can "forward" or "include"
• Called resource is typically a servlet or JSP
• Called resource must be part of this "application"

82 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

There are many ways of designing applications. One design principal, which has
been around for a while, is to break your application down into three logical
parts: the business logic, or Model; the user interface, or View; and something
that binds these together, the Controller. This design idiom, the Model, View,
Controller, or MVC is equally as relevant in the web application world.
Why is MVC so important? Coding servlets is fairly straightforward; getting
servlets to produce HTML is equally straightforward. The problem arises when
your company decide to change the layout of their web pages. If all the web
pages are produced by servlets you would need to go back and edit all the
servlets. On the flip side, suppose all your web site was defined in JSPs. Now
the problem is one of code maintenance--managing code in JSPs is not easy.
For example, JSPs are not usually compiled until they are deployed, so the
development cycle is: edit; deploy; compile; test; debug. What we want to do
is break the work across servlets and JSPs, get the servlets to manage the
logic, and the JSP to manage the user interface.
So we want the servlets to execute code, and JSPs to manage the output,
but how do they communicate? The answer lies to two parts, servlets have to
be able to "call" JSPs (and other servlets) and vice versa. And when making a
call, servlets need a way of passing data to the JSP; enter Java Beans.
In our world, servlets act as the controllers and all (or most) initial requests
are made to a servlet. When building an application around using servlets as
the controller, there are many idioms we could use. The two extremes are:
have only one servlet in your application, this handles all the requests and
decides what logic to execute; or you could have one servlet for each possible
request made to the application. In either case the servlet will check the
request parameters and make sure the request is valid, if it is, it will then
create a bean, and get the bean to execute the logic necessary to carry out the
request. The bean is the Model.
The bean stores the results of its processing logic in its data members. After
the bean has finished its work control returns to the servlet. If we want to send
output back to the client the servlet will now transfer control to a JavaServer
Page. That is the point of this chapter!
To transfer control from one servlet to another (a JSP is just a servlet at
heart), a RequestDispatcher is needed. You get a RequestDispatcher
from the ServletContext, which typically means that you only dispatch into
the current web application. (While it is possible to get ServletContext's for
other web applications, in practice this is likely to prove impossible because of
security risks). When calling getRequestDispatcher you specify the URL of
the resource you want to call. This URL is relative to the current context root
and must start with a "/". You can also call the ServletRequest object's
getRequestDispatcher method. This method allows you to specify a
request relative location path, i.e. the URI doesn't have to start with a "/" and
so the value can be relative to the current servlets location on the server.

Copyright © 2001, DevelopMentor Inc. 83


Module 2: Servlets i

In either case, after retrieving the request dispatcher, the code can then use
it to call another servlet. (In fact you can dispatch to any resource in the web
application, a servlet, a JSP or even static resources such as an HTML page).
You dispatch the call by calling the RequestDispatcher's forward or
include method. We will examine the difference between these in a moment.
Figure 2.11 shows this in action.
ServletContext ctx = getServletContext();
// forward request to Diary servlet
RequestDispatcher rd = ctx.getRequestDispatcher("/Diary");
if(reqd != null){
reqd.forward(req, resp);
return;
}
Figure 2.11: Request Dispatching Example

Be aware that this call is synchronous and that control will return to the servlet
after the call has been completed. Also be aware that the call through the
request dispatcher will probably take the same path to the servlet as a normal
request would, i.e. any container specific code that needs to execute, will do
so before the servlet gets called.

84 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Forwarding Data in the Request


When forwarding requests

• Request and response objects are passed on


• Request data is available to called servlet
• Calling servlet can add data
• request.setAttribute()
• Called servlet can access data
• request.getAttribute()

86 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

So we've seen how to pass control to another resource by using the


RequestDispatcher. If the original request had any request data, this data
will also be available to the called servlet, so the called servlet can use
getParameter, etc. In our MVC idiom outlined above, the original servlet acts
as a controller, and will probably create a bean (the model) to execute the
business logic. When the servlet transfers control, it has to somehow make the
bean available to the called servlet. We can do this by adding the bean to the
ServletRequest object, so that when control is transferred, the called
servlet can reach into the request object and get a reference to the bean that
was put there. Figure 2.12 shows this. (It is possible to give the bean other
lifetimes, for example, session and application. We will see how to do this
later).
MyBean b = new MyBean();
request.setAttribute("bean", b);
reqd.forward(req, resp);

...

MyBean b = (MyBean)request.getAttribute("bean");
// do something with bean
Figure 2.12: Passing and Accessing Request Data

Copyright © 2001, DevelopMentor Inc. 87


Module 2: Servlets i

Request Dispatching Issues


There are certain things to be aware of

• Can't forward after PrintWriterhas been flushed


• If writer hasn't been flushed, it will be cleared
• Forwarding servlet can't use PrintWriter after calling forward()
• Can also "include" resources
• Above limitations don't apply
• Forward URI is relative to ServletContext
• Can specify query strings in request dispatcher path
• getRequestDispatcher("/servlet/Diary?date=today");

88 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Unfortunately there are certain restrictions you have to be aware of when


using request dispatching. Remember that the PrintWriter or
ServletOutputStream used when sending data back to the client may not
be buffered. Now, suppose that the servlet you are forwarding to tries to set
an HTTP response header. If the forwarding servlet has already written data
down to the client, the headers would have been flushed, and the called
servlet would fail in its attempt! Because of this, when a servlet calls forward
the forward fails if any data has been sent back to the client. If the data is
buffered, the forward succeeds, but the buffer is emptied before the forward
takes place. Remember also that the call to forward is synchronous and that
control returns to the calling servlet after the dispatch. When control returns
to the calling servlet, the output stream/writer is closed. This means that the
calling servlet cannot write any data after the call to forward. Notice that in
figure 2.11 there is a return statement after the call to forward.
What about include? include and forward are logically different.
forward is a logical transfer of control whereas include means, "include the
output of the thing I'm calling as part of my output". This means the above
restrictions on the calling servlet do not apply. However, a servlet that has
been dispatched to by an include cannot set any HTTP response headers.
Note that these restrictions get eased in the Servlet 2.3 specification as it is
possible to "wrap" the request and response objects. This means that when
using forward or include, you don't have to pass on the original
HttpServletRequest and HttpServletResponse that you received in the
service method, so you can capture any output the called servlet tries to
send and manage it yourself.

Copyright © 2001, DevelopMentor Inc. 89


Module 2: Servlets i

Configuring Web Applications


Configuring applications is a key aspect of writing
Java-based Web applications. Application
configuration has two parts: server specific and
server independent. Both will be examined.

Copyright © 2001, DevelopMentor Inc. 91


Module 2: Servlets i

Configuration
We just talked about lots of programming

• Configuration is extremely important


• EJB deployment
• Web deployment
• Already seen servlet configuration

92 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Throughout this chapter we've talked about configuring servlets, and about
deployment descriptors. Here we go into a little more detail on the deployment
process.

Copyright © 2001, DevelopMentor Inc. 93


Module 2: Servlets i

Container Configuration
Configuring a web server is proprietary

• Web server must provide a way to map incoming URI to an application


• Virtual directories map to some physical location
• GET /books/getbook HTTP/1.1
• "books" is the virtual directory (the application "name")
• "webapps/books" is the location

94 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

There are two parts to the deployment story: there is a container specific
story, such as how does the container map a URI onto a web application; then
there is the standard part of deployment, for example, what class files make
up a web application. Each web server will have its own internal configuration,
i.e. where it puts .html files, where it puts .class files etc. So long as the web
server can map a URI onto these resources and treat them all as a single
application, separate from the other web applications, we don't care where the
container stores the files. As another example, the container may not even put
the files onto the file system. They may go into a database and be retrieved
using SQL. Tomcat stores all the files associated with a single web application
under one directory. By default, each directory under tomcat\webapps is a web
application.
Tomcat's server configuration is described in a file called server.xml in
the \tomcat\conf directory. As far as web applications go, by default, Tomcat
uses the directory name as the base URI of the applications. So if there is a
directory called \tomcat\webapps\fred and somebody browses to
http://server/fred, the "fred" URI is mapped onto the "fred" web application in
the "fred" directory. You can override this default behaviour by adding a
<Context> element to server.xml. Using this element you can map a different
URI to a directory, or map the URI to a fully qualified directory name. You can
also turn on extra debugging information etc. For a simple example of this see
figure 2.13.
<!-- Tomcat Example -->
<Context path="/books" docBase="webapps/books"
debug="9" reloadable="true" />
Figure 2.13: Example Tomcat Configuration

Copyright © 2001, DevelopMentor Inc. 95


Module 2: Servlets i

Application Configuration
For Deployment

• Each virtual directory contains a directory hierarchy


• Root of hierarchy serves as the document root
• Must have a subdirectory (WEB-INF) that contains configuration and code
• App should be deployed as a .WAR file
• Container is free to "expand" as it sees fit

96 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

While a server is free to configure itself anyway it sees fit, developers don't
want to have the chore of having to understand every server's configuration
quirks just to be able to deploy an application. Because of this, the servlet
specification defines a standard directory structure for deploying applications.
That structure is shown in figure 2.14. The idea is that any web application has
a root directory. This root directory could contain files or subdirectories. These
files would be the static resources and JSP pages that make up the application.
The root directory MUST contain a WEB-INF subdirectory. This directory
contains the deployment descriptor, a file named web.xml, an example of
which is shown in figure 2.15. The WEB-INF subdirectory also contains the class
files and jar files that make up the application. These go in WEB-INF/classes
and WEB-INF/lib respectively.

Figure 2.14: Example of a WAR File

Copyright © 2001, DevelopMentor Inc. 97


Module 2: Servlets i

<web-app>
<servlet>
<servlet-name>Logon</servlet-name>
<servlet-
class>com.develop.timereports.Logon</servlet-class>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:odbc:Football</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Logon</servlet-name>
<url-pattern>/Logon</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>logon.html</welcome-file>
<welcome-file>logon.jsp</welcome-file>
</ welcome-file-list >
</web-app>
Figure 2.15: Example Application Configuration

An application deployer packages this structure into a file with a .war


extension. A .war file is just a Java archive with a different extension. To
deploy the application, this war file has to be passed (deployed) to the server
(how this is done is server specific). All servers must understand this format.
What the server does to the war file is entirely down to the server. Tomcat
expands the war file leaving the structure intact. Other servers may decide to
leave the war file on disk and extract the resources as it needs to. Yet other
servers may split the war file into multiple locations on disk. Whatever they do,
the war file is, logically, the application!
The web.xml file is the deployment descriptor, it is defined by the
specification, so, again, must be understood by all compliant containers. The
descriptor can hold information such as servlet names, servlet mappings,
initialisation parameters, security configuration, listeners, filters etc. In fact,
any declarative information that effects the application goes here.

98 Copyright © 2001, DevelopMentor Inc.


Module 2: Servlets i

Summary
• Servlets perform server-side processing
• Servlets have a generic architecture
• But HTTP servlets are used most often
• HTTP servlets give access to HTTP request
• HTTP servlets create an HTTP response
• One servlet can "call" another
• Servlets are deployed as part of a web application

Copyright © 2001, DevelopMentor Inc. 99


Module 3

JSP

Copyright © 2001, DevelopMentor Inc. 101


After completing this module, you should be able to:
 explain the architecture of JavaServer Pages
 understand how to use 'script' on a page
 explain how to manage a page through page directives
 explain how to use JavaBeans on a page
 explain what how JSP Actions are and how they work

102 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

Introduction to JSP
JavaServer Pages are a great way of producing
dynamic textual content on the web. They use
JavaBeans to hold data, and use Java as the page
"scripting" language.

Copyright © 2001, DevelopMentor Inc. 103


Module 3: JSP

Why JSP?
Servlets good at Logic, JSPs good at UI

• Servlets are not so good at producing large amounts of output


• out.write() is ugly
• JSPs are great at producing lots of textual output
• Not so good at lots of logic: <% %> is ugly

104 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

JSPs are just servlets under another guise. So, why do we have JSPs? The
answer comes back to the idea of being able to break an application up into
distinct parts, the model, view and controller. Servlets function very well as
controllers, they are good at executing logic, and follow the traditional: write;
debug; test; development model. Conversely, servlets are not an ideal choice
for producing output. While producing the output isn't difficult (it's just a
matter of calling out.write()), applying formatting, or changing the layout
of the output at a later stage is difficult .
JavaServer Pages on the other hand are very good at taking the "view" role in
MVC. JSPs are good at producing textual output, either XML or HTML. JSPs are
not as good for logic. Including Java on a JSP is problematic. You have an extra
step before doing a compile (you need to deploy to the web server first) and
Java code in a JSP is difficult to debug
JSPs and servlets are typically used together using the MVC idiom (many Java
sources call this the Model 2 architecture). In this model, Servlets act as the
controller, beans as the model and JSPs as the View. Figure 3.1 shows this in
action. A request typically comes into a servlet; that servlet then uses a bean
(creating it if necessary) to execute the business logic, and hold the results of
this processing. A RequestDispatcher is then used to forward control to a
JSP. The JSP extracts the data from the bean, and sends the view back to the
client.

Client Servlet RequestDispatcher JSP

1: Request()

2: [if exists = "false"]: New()


Bean

3: execute()

4: Delegate()

5: Dispatch()

6: RetrieveContent()

Figure 3.1: Interaction Between a Servlet and a JSP

Copyright © 2001, DevelopMentor Inc. 105


Module 3: JSP

How does it work?


JSP Page is ...

• Mixture of text, Script, actions and directives


• Text could be text/html, text/xml or text/plain
• Compiles page to servlet
• Executes servlets service() method
• Sends text back to caller

106 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

A JavaServer Page is a collection of static text (plain text, HTML, XML or some
other format), script (in blocks), directives and actions. As figure 3.2 shows,
the page is translated into a Java servlet, the servlet is compiled, and the
resulting class executed. The client sees the result of this execution NOT the
original page.
MyJSP.jsp
<%@response.setContentType
<% page contentType="text/xml"
("text/xml");
%> %>
<response>
<name>Password</name>
<value>
<% out.write("Fred"); %>
</value>
</response>
produces this
public void service(…){

JspWriter out = pageContext .getInitialOut ();

response. setContentType ("text/ xml");
out.write("<response><name>Password</name>");
out.write("<value>"); Client sees this
out.write("Fred");
out.write"</value></response>"); <response>
} <name>Password</name>
<value>Fred</value>
</response>

Figure 3.2: Translation and output of a simple JSP

Copyright © 2001, DevelopMentor Inc. 107


Module 3: JSP

Intrinsic Variables
JSP page has a set of pre-defined variables available

• javax.servlet.jsp.PageContext pageContext
• java.lang.Object page
• javax.servlet.http.HttpServletRequest request
• javax.servlet.http.HttpServletResponse response
• javax.servlet.http.HttpSession session
• javax.servlet.ServletContext application
• javax.servlet.jsp.JspWriter out
• javax.servlet.ServletConfig config

108 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

When developing servlets you typically override one of the doXXX helper
methods. These methods get passed a request object and a response
object. In the servlet you may want to output text. To do this you call
request.getWriter() to access the PrintWriter. You can also declare and
access the ServletContext and ServletConfig objects, along with a
session variable. In JSP these objects are automatically made available to
the script on the page. Remember that JSPs are compiled to servlets. The
generated servlet code simply declares and initializes these variables for us to
use. A basic version of the generated servlet looks like figure 3.3. Notice that
the main method is not service but _jspService. This allows us to create a
base class that implements service and have that setup our environment
before calling _jspService
public class Browse_jsp extends HttpJspBase {
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException {

JspFactory _jspxFactory = null;


PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;

// etc...
Figure 3.3: Simplified View of the Generated Servlet Code

We've met most of these variables already (such as the request and
response variables), or will study them in more detail later (session). There
are three we haven't seen before: page, pageContext and JspWriter.
page is a synonym for this, JSP authors are not supposed to be Java
programmers, and explaining the concept of this was thought to be too
difficult, whereas page is easy to understand.
The pageContext is both a factory and a container. It is used to create
many of the other objects needed on the page, and also holds a reference to
those objects. We will see the pageContext used later when we look at actions,
and again when we look at tag libraries.
Finally, there is the JSPWriter the out variable. JSPWriter is derived
from PrintWriter, but JSPWriter is buffered, whereas PrintWriter was
not. JspWriter's print methods throw IOExceptions.

Copyright © 2001, DevelopMentor Inc. 109


Module 3: JSP

Producing Output
JSPs produce textual output

• <book name="JSP" />


• <% out.write("Homer Rules"); %>
• <value>value is <%= b.getValue() %></value>

110 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

There are several ways for a JSP to produce output. Any "static" text that
appears on the page is written back to the client verbatim, and any script block
can call out.write(). These are functionally equivalent, remember the page
gets compiled to a servlet and any static text gets turned into out.write()
method calls. JSP introduces the concept of "expressions". An expression is a
piece of code that produces a string (i.e. anything you can call toString on.),
the JSP syntax for expressions is <%= bean.someMethod() %>, this produces
out.print(bean.someMethod()). The resulting generated code looks like
figure 3.4.
out.write("<book name='JSP' />");
out.write("Homer Rules");
out.print("<value>value is " + b.getValue() + "</value>")
Figure 3.4: Produce Code

Copyright © 2001, DevelopMentor Inc. 111


Module 3: JSP

Script
Java is currently the language of JSPs

• Script is of form <% /* code goes here*/ %>


• Gets copied into _jspService method of generated servlet
• Any valid java can go here

112 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

JSP allows for any language to be used on the page, with certain caveats. For
example, any language that is used must have full access to Java packages,
which means the standard JDK libraries are available. Today however, the only
language supported when writing JSPs is Java itself. As shown in figure 3.5,
script must appear in a <% %> block. Script can be intermixed with static
content, and the script can be any valid Java code. The script in figure 3.5
generates the code shown in figure 3.6. Notice that all the code is generated in
the _jspService method of the generated servlet.
<% int j; %>
<% for (j = 0; j < 3; j++) {%>
<value>
<% out.write(j); %>
</value>
<% } %>

this JSP produces this output -

<value>0</value>
<value>1</value>
<value>2</value>
Figure 3.5: Code in a JSP

public void _jspService(...)


{
int j;
for (j = 0; j < 3; j++) {
out.write("<value>");
out.write(j);
out.write("</value>");
}
Figure 3.6: Generated Java Code

In JSP we can also define variables and methods at class scope, i.e. instance
variables, and helper methods. We do this by using the declaration syntax.
Figure 3.7 shows an example of this.

Copyright © 2001, DevelopMentor Inc. 113


Module 3: JSP

<%! int j; %>

public class SomeJSP extends HttpServlet,


implements HttpJspPage {
...
int j = 0;
void _jspService(...) {
...
}
}
Figure 3.7: Use of Declarations in JSP

114 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

Directives
Used to control various aspects of the generated code

• Page
• Include
• Taglib
• Of form <%@ directive attr_list %>

116 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

There are many things on that page that we would like to control, but that are
outside the scope of any Java code that we could write. For example, we may
want to set the size of the buffer for the JSPWriter, but we cannot do this in
script. To allow us to manage these aspects of a page, we have directives.
Directives are commands sent to the JSP engine, and there are three types,
taglib, include and page. Figure 3.8 shows how directives are defined.
Notice the <%@ symbols for the start of the directive. JSP 1.1 also introduced
an XML syntax for directives, this is the <jsp:directive. syntax.
<%@ page info="written by DevelopMentor" %>
<jsp:directive.page import="java.sql.*" />
<%@ include file="\somefile.txt" %>
<%@ taglib uri="tags" prefix="foo" %>
Figure 3.8: Use of Directives on a Page

What do the three directive types do? The taglib directive we will deal with
later. Figure 3.9 shows the include directive. This basically allows us to
include other text in this page. The include is a compile time include, i.e.
the included text is copied into the page before the page is compiled. The
canonical use of this is to divide a JSP page into common parts, such as headers
and footers, then to include those parts in (possibly) all the JSP pages that
make up the site. NOTE, the include directive is a compile time include,
whereas the RequestDispatcher.include is a runtime include, i.e. a
method call.
<%@ include file="\somefile.txt" %>
<%@ include file="\somefile.jsp" %>
Figure 3.9: Example of Include Directive

Finally, the page directive. This allows us to set many of the aspects of the
page. Figure 3.10 shows the parameters to the directive and their meanings,
most of which are self-evident, some that we haven't come across yet. With
JSPs you can define a error pages, which are pages that you want executed
when an exception is thrown in a JSP. An error page has the isErrorPage
directive set to true. To associate a JSP page with a specific error page, the
JSP page specifies the errorPage attribute.

Copyright © 2001, DevelopMentor Inc. 117


Module 3: JSP

Attributes What does it do Default


extends class that the servlet extends none
import classes imported into servlet none
isThreadSafe if false implements SingleThreadModel true
buffer JSPWriter buffer size 8kb
autoFlush should JSPWriter flush if full true
session automatic session true
errorPage what is the error page associated with this page? none
isErrorPage is this page an error page? false
language what is the scripting language Java
info getServletInfo none
contentType content type of the generated page text/html
pageEncoding character encoding of the generated page ISO-8859-1

Figure 3.10: JSP Page Directive Usage

118 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

JSP Actions and JavaBeans


Java Beans are the components used by JSPs. They
are the 'model' in the MVC architecture. Java Beans
are accessed and managed in JSP through a special
syntax known as JSP actions.

Copyright © 2001, DevelopMentor Inc. 119


Module 3: JSP

What are beans?


Java Components that follow standard naming conventions

• Must have a default constructor


• Must be Serializable
• Typically have get methods for property access
• Typically have set methods for property access

120 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

Java Beans are Java objects that follow a simple set of rules. At the most basic
level a Bean is an object with a default (no-args) constructor, and is
Serializable. Beans will typically have properties, i.e. data that is available to
users of the bean. Beans typically make these properties available through get
and set methods. Property names and method names follow a convention, the
property name starts with a lowercase letter, while the part of the set/get
name following set or get, starts with an uppercase letter. So if we have a
property called age the methods would be called setAge and getAge. Bean
containers will use reflection to discover the beans properties. Figure 3.11
shows an example of a simple bean.
public class DiaryTable implements
java.io.Serializable
{
String startDate;
Vector rows;
public DiaryTable() throws Exception {
}
public String getStartDate(){
return startDate;
}
public void setStartDate(String strDate){
startDate = new String(strDate);
}
public Row getRow(int nIndex) {
return (Row)rows.elementAt(nIndex);
}
}
Figure 3.11: Simple Bean Showing Property Gets and Sets

If beans don't follow this naming convention they can supply information about
their properties to the container by passing in a java.beans.BeanInfo
instance. This class has getPropertyDescriptors and
getMethodDescriptors methods that provide detailed information about
the bean. Many Java classes are beans: most of the base JDK classes have a
default constructor and are serializable (the minimum necessary to be a bean).
JSP defines a special syntax to allow us to define, create, and use beans.
The syntax is called standard actions (there are also custom actions AKA
taglibs, we will talk about these later). JSP also allows us to use Java code on
the page, and in that Java code we can create and use instances of Java
classes, i.e. beans. So what's the advantage of using standard actions? The
standard actions encode certain common usage patterns but there is nothing
you can do in a standard action that you cannot do in script: JSPs are just
servlets after all. The main advantage of actions is they are not Java code.
Remember that the main audience for developing JSPs is not programmer, but

Copyright © 2001, DevelopMentor Inc. 121


Module 3: JSP

page designers. We shouldn't expect page authors to understand Java, and


'actions' hide the complexity of Java from them.
Figure 3.12 shows how to create a bean using a standard action and the
equivalent code in a script block.
<jsp:useBean id="dte"
class="java.util.Date" />

<% java.util.Date dte = new


java.util.Date(); %>
Figure 3.12: Initializing a bean using an action, with the generated code.

122 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

jsp:useBean
useBean defines a bean for use on this page

• ><jsp:useBean id="dte" class="java.util.Date"


scope="request" />
• Bean may be created and initialised
• Bean may already exist in a 'scope'
• Scope is one of 'page', 'request', 'session' or 'application'

124 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

The jsp:useBean action actually does more than simply create a bean, which
is what the previous code showed. The useBean action first checks if the bean
already exists in this scope. Think back to the MVC scenario, the example we
gave was of the servlet creating a bean, putting a reference to the bean into
the request object, then forwarding to the JSP. How does the JSP access the
bean?. The jsp:useBean action has a parameter to specify the 'scope' of the
bean, in this case the scope would be 'request'. Figure 3.13 shows how this
works.
<jsp:useBean id="dte"
class="java.util.Date"
scope="request" />

/* ------------------ the Java code ------------------ */


java.util.Date dte = null;
dte=(java.util.Date)pageContext.getAttribute(
"dte",
PageContext.REQUEST_SCOPE);
if ( dte == null )
{
dte =(java.util.Date)Beans.instantiate(
getClass().getClassLoader(),
"java.util.Date");

pageContext.setAttribute("dte",
dte,
PageContext.REQUEST_SCOPE);
}
Figure 3.13: Creating a bean using an action, and the equivalent script
block

So what's happening here? The generated code first defines a variable of the
right type (the name of the variable is the id value of the useBean tag). We
then check to see if the bean already exists in the scope specified in the
useBean tag ('request' scope in this case). The check is made via the
pageContext object (remember this is container for other objects). If the
bean exists, the variable just defined is initialised. However if the bean does
exist in this scope, an instance is created and assigned to the defined variable,
and the bean is then stored in the appropriate scope.
So what are the various scopes.
'page' says that the lifetime of bean is for this page (i.e. this servlet) only.
This means that if I dispatch to another servlet, that servlet will not be able to
get a reference to this instance of the bean.

Copyright © 2001, DevelopMentor Inc. 125


Module 3: JSP

'request' is the scope we've used so far. This says that the lifetime of bean is
for this request only. This means that if I dispatch to another servlet, that
servlet will be able to get a reference to this instance of the bean, but another
request cannot see this instance
'session' says that the lifetime of bean is for this users session. This means
that any servlet invoked by any request from this user gets to see this instance
of the bean.
And finally 'application' says that any request from any user in any session
gets to see this instance of the bean.

126 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

Accessing Bean properties


There are standard actions for property access

• jsp:getProperty
• jsp:setProperty
• both actions specify a bean and a property name
• setProperty can specify a value to set
• setProperty can specify that values are set from the incoming HTTP request

128 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

We now know how to create and get references to beans, but how do we
access bean properties? There are two standard actions for property access,
jsp:getProperty and jsp:setProperty. As figure 3.14 shows
getProperty is easy to understand.
<jsp:getProperty name='Diary'
property='startDate' />

<% out.write(Diary.getStartDate()); %>


Figure 3.14: Using jsp:getProperty

jsp:setProperty is a little more complex. It has a fairly simple usage that


figure 3.15 shows. The jsp:setProperty takes the bean name, the name of
the property to set, and the value of that property, which can be a hard coded
or calculated value.
<jsp:useBean id="dataBean" scope="page" class="DataBean" >
<jsp:setProperty name="dataBean"
property="userId"
value="abcde" />
</jsp:useBean>
Figure 3.15: Setting a Bean Property With a Value

The other form of setProperty is shown in figure 3.16. Here we are setting the
value of the property from a request parameter. The first example shows a
property named with the 'property' attribute, being initialised from a request
parameter named from the 'param' attribute. This (logically) results in code
like this dataBean.setUserId(request.getParameter("name"));
<jsp:useBean id="dataBean" scope="page" class="DataBean" >
<jsp:setProperty name="dataBean"
property="userId"
param="name" />
</jsp:useBean>

<jsp:useBean id="dataBean" scope="page" class="DataBean" >


<jsp:setProperty name="dataBean"
property="*" />
</jsp:useBean>
Figure 3.16: Setting a Bean Property From Request Parameters

In the second example we specify '*' as the param name, and no property value.
The generated code will try to do a one-to-one mapping of request parameter
name with property name, and set the value of the bean property from the
matching request parameter.

Copyright © 2001, DevelopMentor Inc. 129


Module 3: JSP

One issue that we haven't touched upon yet is bean initialisation. Beans are
Java objects with default constructors, which means that the typical use of a
bean will create that bean in a vanilla state. In that case, how do I initialise
the bean before use? This is achieved in JSP by adding code to the body of the
useBean tag. Any code in the body of the tag is only executed when the bean
is first created. So, for example, if a request comes into a JSP and that JSP has
a useBean tag with 'request' scope, that JSP will create the bean. If the
useBean has a body, that body will execute. If the JSP then forwards to
another JSP, and that JSP has a useBean tag for the same bean also with
request scope, that bean will not be created, but will be pulled from the
request object. If the useBean tag has a body, the body will NOT be executed.
The body of the useBean tag is (morally) its constructor. Figure 3.17 shows an
example of a bean with a body.
<jsp:useBean id="dte" class="Date" >
<jsp:setProperty name="dte"
property="time"
value="0" />
<% helperfunction(); %>
</jsp:useBean >
Figure 3.17: Initializing a Bean

One last thing to note with jsp:setProperty. The 'value' attribute is a string (as
is any attribute). The JSP container will try and convert this to the correct
property type before it calls the set method. So if the property is an int and
the value of the jsp:setProperty 'value' attribute is '5' then the string '5'
gets converted to the integer 5 and the call succeeds. However if the value was
a 'java.lang.Integer' then the conversion would fail. The container will convert
between strings and all the primitive types. But what happens if the property
type is not a primitive, but is an object type? In that case there is a special
syntax that can be used. The syntax is shown in figure 3.18, and the value is
called a request time attribute value. When the container sees this syntax, it
uses reflection to discover the type of the 'date' property, and simply calls the
setDate method passing dt as a parameter, like this
startDate.setDate(dt).

130 Copyright © 2001, DevelopMentor Inc.


Module 3: JSP

<jsp:useBean id="dataBean" scope="page" class="DataBean" >


<jsp:setProperty name="dataBean"
property="userId"
value="<%= logonBean.getUserId() %>"/>
</jsp:useBean>

<jsp:useBean id="startDate" scope="page"


class="java.util.Calendar" >
<!-- dt is a date object -->
<jsp:setProperty name="startDate"
property="time"
value="<%= dt%>" />
</jsp:useBean>
Figure 3.18: Setting a Bean Property With an Attribute Value

Copyright © 2001, DevelopMentor Inc. 131


Module 3: JSP

Summary
• JSPs can be used as the view in the MVC architecture
• JSP uses Java as the script language
• The generated servlet can be managed by directives
• JSP encourages the use of Java Beans
• Beans are accessed through actions

132 Copyright © 2001, DevelopMentor Inc.


Module 4

EJB Introduction

Copyright © 2001, DevelopMentor Inc. 133


Programming by specifying intent declaratively

After completing this module, you should be able to:


 understand the EJB programming model
 learn how to develop and deploy a bean
 learn how write a client to locate and call a bean

134 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

Introduction to the EJB model


EJB offers a container that provides services for
Java components. The communication mechanism
used by EJB is RMI.

Copyright © 2001, DevelopMentor Inc. 135


Module 4: EJB Introduction

The EJB Way


What is EJB?

• Interface-based programming model


• Services provided by a container
• Several Bean types that must be written as EJB components
• Uses RMI as the communication protocol
• Uses JNDI as the "lookup" protocol

136 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

In a three-tier distributed system, business logic is taken from client machines


and deployed on middle-tier machines where it is easier to manage and can be
shared among thinner clients. If such code is exposed as fairly coarse-grained,
tasks-based operations this can result in reduced round-trips and connections
from the client. It also allows the middle-tier to provide centralized services
such as data caching, object-relational mapping resource pooling (recycling),
security authentication and authorization control, concurrency control and
transactions.
On an intranet where Java is deployed on both client and middle-tier, it is
natural to use RMI to communicate between them. Shared business logic is
encoded as RMI objects, deployed in an RMI server and exposed across the
network. RMI is a protocol for communicating with remote Java objects and
says nothing about how such an object might manage its (possibly distributed)
state in this environment. It is hard to write such a server that functions
correctly in the face of concurrent client access. The RMI developer is
responsible for developing the middle-tier services mentioned above.
An EJB server is essentially an RMI server, "on steroids". EJB containers offer
services in a single place such that all components deployed in the container
can take advantage of them. So for instance, as well as dealing with the RMI
communications plumbing it also provides important state management
services, such as transactions.
Because of the services it provides and the programming model it
introduces, an EJB server does add a lot of overhead in terms of memory used
and raw speed of execution (the two are related of course). For middle-tier
code accessible via an internet, where Java is not necessarily used on the
client, or in situations where performance is a concern, then HTTP +
Servlets/JSP + JDBC may be a serviceable solution. The developer would need
to manage concurrency by hand but the benefit would be lower overhead and,
arguably, better performance. However, concurrent access to shared, read-
write persistent data requires transactions. This is manageable in the simple
case where one component uses local transactions to access a single resource
(such as a single database). However, if a single transacted operation uses a
single resource but is composed from multiple server-side components (such as
Servlets, JSPs, beans) then propagating and sharing the transaction and its
resource in a non-intrusive fashion becomes a challenge. In the case of multi-
component/multi-resource transactions, then some kind of distributed
transaction processing (TP) monitor is needed and the programming model for
propagating/enlisting the transaction and ensuring safe committal of data is
more complicated still. It is reasonable in either case to expect that
transaction outcome be controllable from anywhere in the execution path and
for transaction propagation/enlistment to be implicit. Servlets and JSPs
provide no support here.
So in the intranet or internet scenario, EJB provides sought-after services. It
turns out also that the programming model it introduces and the interception

Copyright © 2001, DevelopMentor Inc. 137


Module 4: EJB Introduction

framework it provides yield other potential benefits too. EJB, though, is


primarily a specification for Java-based TP monitors.
EJB is a specification, not an implementation that builds on existing Java
technologies, such as RMI, JTA, JNDI, JDBC, JMS etc. The EJB interception
architecture and programming model correlates very closely to MTS and COM+
in the Microsoft space. The current specification is 1.1 and that is what is
discussed here. There is a new 2.0 specification in final public draft format at
the moment that is a refinement to the 1.1 specification.
An EJB container is an RMI server that interacts with its deployed
components in a manner prescribed by the specification. Containers are
available from several vendors and, whilst they adhere to the specification,
they all add value outside of what the specification defines and all work in
slightly different ways! Sun provides a reference implementation (J2EE) so you
can always see what a minimally compliant EJB container implementation
should do, however, the license agreement for the J2EE server prohibits its use
commercially.
Currently all client access to EJB components is via RMI (although this is set
to change with the introduction of message-driven beans in EJB 2.0). RMI/IIOP
is now the preferred protocol (and is mandatory as of EJB 2.0) as IIOP can be
used to interoperate with the CORBA world.

138 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

Remote Procedure Call


RMI is Java's version of RPC

• Java syntax
• Request / response semantics
• Latency
• Communications failures
• Parameter serialization

140 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

RMI is Java's version of Remote Procedure Call (RPC). When you use an RMI
object, you use Java syntax as normal. Behind the scenes, the method call is
serialized into a request, which is then forwarded to the implementation,
which typically resides on another virtual machine across the network. The
server deserializes the request, invokes the method, and serializes a response
that is sent back to the caller. The response is then deserialized, and the caller
sees the return value or exception that resulted from the call.
The strength of RMI (and RPC in general) is its familiar syntax. However, RMI
objects are fundamentally different from normal objects, and their design must
take this into account. Limited by network protocols and ultimately by the
speed of light, the requests and response introduce latency into the system.
This latency may increase the overhead of method invocation by a million fold
or more.
When objects are passed to an RMI method, they cannot be passed as simple
references because the references will not be valid on the remote server.
Instead, RMI must define some way to serialize parameters into the request and
response messages. Either Java Serialization or some other type-information
driven scheme must be used. This changes method semantics, because changes
to call parameters on the server side will not be visible on the client.

Copyright © 2001, DevelopMentor Inc. 141


Module 4: EJB Introduction

Commingling of concerns
RMI sets syntax, wire protocol, and endpoint semantics

• Should be separate concerns


• Difficult to pick and choose
• Two all-or-nothing choices: JRMP and IIOP

142 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

RMI is a relatively complete solution. You get a Java syntax, a wire protocol,
and endpoint semantics all rolled together. In some situations, it might be nice
to separate these pieces and pick and choose what you need. For example, it
might be nice to have RMI language mappings over an XML-based wire protocol.
Or, it might be nice to have an RMI client transparently call to a Servlet instead
of an RMI server.
It is relatively difficult to pick and choose pieces of RMI, because the
architecture is not factored to permit this. Instead, there are two choices:
JRMP and IIOP

Copyright © 2001, DevelopMentor Inc. 143


Module 4: EJB Introduction

Java Remote Method Protocol (JRMP)


JRMP is the original RMI protocol

• Object serialization
• Distributed GC
• Preferred by the JINI crowd

144 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

JRMP is the original RMI protocol. JRMP assumes Java end-to-end. JRMP uses
Java serialization for object parameters, and provides distributed garbage
collection. The JRMP runtime keeps a reference count for active stubs, and
manages leases by pinging over the network. If a stub misses its ping, the client
is assumed dead, and the reference count drops. If all remote and local
references vanish, the RMI object will be unexported automatically during
garbage collection
JRMP is preferred by JINI developers. JINI is a technology for spontaneous
networking that provides automatic discovery of network services.

Copyright © 2001, DevelopMentor Inc. 145


Module 4: EJB Introduction

Internet Inter-Orb Protocol (IIOP)


IIOP supported by the CORBA crowd

• Objects by value
• No GC
• Split identities
• Preferred by the EJB crowd

146 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

The Internet Inter-Orb Protocol was grafted onto RMI at the behest of EJB and
CORBA vendors, who were often the same people and wanted a common
protocol. IIOP is defined by CORBA, and can be used to interoperate with other
language environments. IIOP is "better" than JRMP in the sense that is mandates
less about who is on the other end of the wire.
IIOP stubs do not perform distributed garbage collection.
IIOP does not guarantee that stub identities will correlate with server object
identities. In other words, a particular server object may be represented by a
group of stub identities on the client. (Often there will be a different stub for
each interface.) This has an important implication for the RMI programming
model: you should not use Java language casts to convert between interfaces
on remote stubs. Instead, you should use PortableRemoteObject.narrow,
which will locate the correct stub. Figure 4.1 shows this distinction. Using
narrow will always work correctly, even if a regular language cast is all that
was needed.
//this is NOT PORTABLE!
TestRMIItf itf = (TestRMIItf)
Naming.lookup("TestRMIServer");

//portable to both JRMP and IIOP


TestRMIItf itf = (TestRMIItf) PortableRemoteObject.narrow(
Naming.lookup("TestRMIServer"),
TestRMIItf.class);
Figure 4.1: Always use PortableRemoteObject.narrow for RMI casts

Copyright © 2001, DevelopMentor Inc. 147


Module 4: EJB Introduction

Introduction to the EJB Programming


Model
An EJB is a strange mix of container interception
code and the developer's code and it is important to
understand the unusual type relationship between
the two. It is not enough to code the bean correctly-
-it must also be deployed properly in order that
client code may access it.

Copyright © 2001, DevelopMentor Inc. 149


Module 4: EJB Introduction

EJB programming model


Managed code, programming by intent

• Bean "declares" services requirements


• Bean code and attributes deployed in EJB container
• Container intercepts all calls to bean
• Interception code provides services

150 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

An EJB is a Java component that follows certain rules so that it can be


deployed in an EJB container. An EJB container provides services to the EJB,
such as method-level access checking and transactions. The EJB declares its
intent and its services requirements via declarative attributes rather than
having to write explicit code. These attributes are defined in an xml-based
"deployment descriptor". For the most part, the bean code concentrates on its
problem domain and assumes that the services it requested are provided by the
container. This style is similar to aspect-oriented programming.
The bean code and the associated descriptive attributes are "deployed" in an
EJB container. At this time the container takes the supplied code and
attributes and uses Java reflection to generate interception code that wraps
access to the bean and provides the services it requested. This technique is
often known as "interposition" or "interception". The container also generates a
factory for the EJB so that it can be created and all the necessary RMI plumbing
code (such as stubs and skeletons) so that it can be accessed remotely which
figure 4.2 illustrates. You will probably want to keep referring to this diagram!

client ejb container


RMI RMI home EJB creates,
finds, de letes
stub skeleton interface home
context
(run-time environment)

RMI RMI remote


EJB object bean
stub skeleton interface

defines services to calls platform code


construct interposer
container generated
developer defined deployment system
services
descriptor

Figure 4.2: EJB interposition model

Copyright © 2001, DevelopMentor Inc. 151


Module 4: EJB Introduction

Writing a Bean
Writing a bean requires five steps

• Define the Home interface


• Define the Remote interface
• Write the bean implementation
• Write the deployment descriptor
• Deploy the bean

152 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

Roughly, the development process is as follows:


1) Define the home interface. This is the RMI interface the client will use to
create the bean.
2) Define the remote interface. This is the RMI interface the client will use
to access the business methods of the bean.
3) Define the bean class. This is the bean implementation and contains,
among other things, concrete implementations of the methods in the remote
interface. It turns out that the bean doesn't actually implement (in the Java
sense) the remote interface but rather provides matching methods. More on
this later.
4) Define the deployment descriptor. This ties together the remote
interface, home interface and bean class and specifies the services required by
the bean. It also gives the bean a JNDI name so that it can be found by the
client.
5) Deploy the bean. Give the deployment descriptor, remote interface,
home interface and bean class to the container deployment tool and it will
generate a whole load of support code. Most importantly it will generate an
implementation of the home interface on the factory (EJB Home), the remote
interface on the interposer (EJB Object) and RMI stubs and skeletons to allow
the client to use both the home and remote interfaces. Notice how the
interposer pre- and post-processes each call to our bean. This is so it can
establish the correct run-time context for the bean and provide it with the
services it needs to function correctly.
6) Assuming the server is running, it will have bound the factory (EJB Home)
into its JNDI context with the JNDI name specified in the beans deployment
descriptor. This allows the client to perform a JNDI lookup to obtain the home.
7) The client locates the server's JNDI context and performs a JNDI lookup,
using the JNDI name specified in the bean's deployment descriptor, to obtain a
reference to the beans home interface. From this it can create or locate the
bean and gets back a reference to the beans remote interface. The client can
now call methods on the bean. This assumes that the client had a way to locate
the RMI stubs for the home interface and remote interface. NOTE: the caller
ALWAYS has a reference to the interposer and NEVER the bean directly. If this
were not the case then the container could not intercept calls to the bean and
do "the right thing".
So from the client's perspective the EJB looks like any other remote RMI
object. From the developer's perspective, free services are on offer. No such
thing as a free lunch though, right?
The caller accesses a bean via its remote interface - an RMI interface
defining the business methods of the bean The interface doesn't derive directly
from java.rmi.Remote interface but rather from a subclass

Copyright © 2001, DevelopMentor Inc. 153


Module 4: EJB Introduction

javax.ejb.EJBObject. This way every remote interface inherits some


methods deemed useful to the caller. Some of these will be discussed in later
sections. Typically the remote interface is obtained via the beans home
interface. Here is the definition of the javax.ejb.EJBObject interface.
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
import javax.ejb.EJBHome;
import javax.ejb.Handle;
public interface EJBObject extends Remote {
public EJBHome getEJBHome()
throws RemoteException;
public Handle getHandle()
throws RemoteException;
public Object getPrimaryKey()
throws RemoteException;
public boolean isIdentical()
throws RemoteException;
public void remove()
throws RemoteException;
}

Figure 4.3 shows a typical remote interface. Notice how each method must
be defined to throw a java.rmi.RemoteException. The RMI plumbing will throw
this exception in the case of a communications failure and the container may
throw this exception also (e.g. in the case of a runtime exception being thrown
by the bean). Methods may also optionally be annotated to throw application-
defined exceptions.

154 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

import java.rmi.RemoteException;
import javax.ejb.EJBObject;

public interface TellerSession extends EJBObject


{
public boolean deposit(Money m,Account a)
throws RemoteException, TellerException;
public boolean transfer(Money m,Account a1,Account a2)
throws RemoteException, TellerException;
...
}
Figure 4.3: EJB remote interface

The caller creates or finds a bean via its home interface - an RMI interface
defining factory methods for the bean. In EJB 2.0 it also defines class-level
(instance-less/static) methods for the bean. Again this interface doesn't derive
directly from java.rmi.Remote interface but rather from a subclass
javax.ejb.EJBHome so that every home interface inherits a bunch of extra
methods that will be explored in later sections. Typically the home interface is
obtained via a JNDI lookup as shown later. Here is the definition of the
javax.ejb.EJBHome interface.
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.ejb.EJBMetaData;
import javax.ejb.EJBHome;
import javax.ejb.HomeHandle;
import javax.ejb.Handle;
public interface EJBHome extends Remote {
public EJBMetaData getEJBMetaData()
throws RemoteException;
public HomeHandle getHomeHandle()
throws RemoteException;
public void remove(Handle h)
throws RemoteException;
public void remove(Object pk)
throws RemoteException;
}
Figure 4.4shows a typical home interface. Notice how, in addition
to the obligatory java.rmi.RemoteException we must also indicate that the

Copyright © 2001, DevelopMentor Inc. 155


Module 4: EJB Introduction

container may throw an javax.ejb.CreateException if the bean cannot be


created for any reason. It turns out that the methods in the home interface are
entirely dependent on the bean type (stateful/stateless session or entity). We
have chosen to implement a stateless session so it has a single no-arg create
method that returns a reference to the remote interface we use to access the
bean. A stateful session could have more complex create(...) methods. Sessions
are transient so can only be created anew. An entity represents persistent data
so it could also have finder methods to locate an existing entity. More on this
later.
import java.rmi.RemoteException;
import javax.ejb.EJBHome;
import javax.ejb.CreateException;

public interface TellerSessionHome extends EJBHome


{
// Stateless session bean home has one no-arg create
method
public TellerSession create()
throws CreateException, RemoteException;
// Stateful session bean home may have more
// arg-based create methods
// Session bean home has no find methods
}
Figure 4.4: EJB home interface (for a stateless session)

Figure 4.5 shows how the bean class pulls everything together. This is the class
that will get instantiated and wrapped by the interposer and will contain the
actual business logic. In this case we are building a stateless session bean so
the class must implement the javax.ejb.SessionBean interface containing
methods that the container expects to call during the lifetime of the bean. The
only mandatory methods in the bean class are those of
javax.ejb.SessionBean. The others are inferred. The bean must
implement: an ejbCreate() method corresponding to the create() method in the
home interface; and methods that match those from the remote interface. If
you get the implementation wrong then the compiler won't pick up the problem
as the compiler doesn't understand this informal relationship, i.e. the structure
of the bean and its interfaces doesn't represent a type relationship the
compiler can comprehend. The problem won't be discovered until deployment
time when the container deployment tool reflects over the interfaces and
classes it is given to see if they have been correctly constructed.

156 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;

// This e.g. is a session bean.

public class TellerSessionBean implements SessionBean


{
// Method signature must "match" create() in home
interface
public void ejbCreate() {...}
// Method signatures mandated by SessionBean interface
public void ejbRemove() {...}
public void ejbActivate() {...}
public void ejbPassivate() {...}
public void setSessionContext(SessionContext ctx) {...}

// Method signatures must "match" those in remote


interface
public boolean deposit(Money m,Account a)
{
}
...
}
Figure 4.5: Bean class (for a stateless session)

It might seem strange that the container cannot just define interfaces that the
bean would simply implement to ensure that it was type compatible with the
containers expectations at run-time. However, it would be hard for the
container to fix the syntax of, for instance, an ejbCreate() methods a priori
because the syntax is not decided until the bean developer defines the home
interface at build-time. We have already alluded to the fact that stateful
session beans and entity beans can have arbitrarily parameterized create()
methods. It could be argued that the bean could implement (using the Java
keyword implements) the remote interface and this would eliminate part of
the problem as the bean would at least then be type compatible with the
remote interface. However, this is not the case for a good reason. Read on...

Copyright © 2001, DevelopMentor Inc. 157


Module 4: EJB Introduction

A Better Way
Bean and Remote disconnected

• Bean and Remote must implement the same methods


• But bean cannot implement remote interface
• Solution: Factor remote methods out into a local interface

158 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

The instantiated bean is a strange mix of developer and container code. The
container provides the remoting, bean management and services while the
developer provides domain-specific behaviour. Remember that the remote
interface is implemented (using the Java keyword implements) by the
interposer (EJB Object) NOT the bean class. The interposer intercepts the calls
to the remote interface methods, provides any required services and then calls
bean class methods with matching signatures. This is an important point. The
bean class IS NOT type compatible with the remote interface. If it were, then a
bean class reference could be passed anywhere a remote interface reference
was required. This could lead to another part of the system getting a direct
reference to the bean instead of a reference to the interposer, and this could
lead to direct calls on the bean without going via the interposer. Giving out
direct access to the bean would be disastrous, since the bean would then not
execute in the run-time environment that it had asked for and was expecting.
Also, if the bean did implement the remote interface it would have to
implement all those methods of javax.ejb.EJBObject that only the
container knows how to implement. Note also that the home interface is
implemented by EJB Home, not the bean class. It does all the work to create or
locate the bean and then calls bean class methods with corresponding
signatures. For instance, for each create(...) method defined in the home,
there must be a corresponding ejbCreate(...) implemented by the bean (which
turns out to be its EJB constructor). More on bean lifecycle later.
So how do we make it harder to make the inevitable mistakes born out of
the lack of standard type relationship between the interposer and the bean?
Well, there is a compromise solution. Define a local interface that contains
only the business methods you want the bean to expose, such as in figure 4.6.
Then use the fact that Java interfaces can use multiple inheritance in their
definition and define a remote interface as in figure 4.7. Now the bean class
can implement the local interface as in figure 4.8 and now the only thing to get
right is the ejbCreate().
import java.rmi.RemoteException;

public interface TellerMethods


{
public boolean deposit(Money m,Account a)
throws RemoteException, TellerException;
public boolean transfer(Money m,Account a1,Account a2)
throws RemoteException, TellerException;
...
}
Figure 4.6: Local interface defining bean methods

Copyright © 2001, DevelopMentor Inc. 159


Module 4: EJB Introduction

import javax.ejb.EJBObject;

public interface TellerSession extends TellerMethods,


EJBObject
{
}
Figure 4.7: Revised remote interface

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
// This e.g. is a session bean.

public class TellerSessionBean implements TellerMethods,


SessionBean
{
// Method signature "match" create() in home interface
public void ejbCreate() {...}

// Method signatures mandated by SessionBean interface


public void ejbRemove() {...}
public void ejbActivate() {...}
public void ejbPassivate() {...}
public void setSessionContext(SessionContext ctx) {...}

// Methods in local TellerMethods interface


public boolean deposit(Money m,Account a)
{
}
...
}
Figure 4.8: Revised bean class (for a stateless session)

160 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

Bean creation
When container creates bean it has two-phase construction

• Container calls Class.newInstance()


• Bean must have no-arg constructor
• Container calls one of setSessionContext()/setEntityContext()
• Context represents bean's ability to interact with its run-time environment
• Valid for bean's lifetime
• Container calls ejbCreate() corresponding to create() in home
interface
• This is where meaningful construction is done

162 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

When the container creates the bean class it does so using


Class.newInstance() so the bean class must have a no-arg constructor. The
easiest way to achieve this is not to provide any constructor at all and force
the compiler to provide one. The bean cannot be initialized in its constructor
anyway, for two reasons. First, any initialization parameters provided by the
client via the create() method in the home interface (assuming it has any)
get delivered to the beans ejbCreate() method. Second, and more
importantly, at the point at which the bean's constructor fires it hasn't been
given its context.
A bean's context represents its ability to interact with the runtime
environment provided for it by the container. It is represented by a subclass of
the javax.ejb.EJBContext interface, javax.ejb.SessionContext for a
session bean and javax.ejb.EntityContext for an entity bean. The
relevant context interface is implemented by the container and given to the
bean at creation time. When the container creates the bean class, the
sequence of events from the bean's point of view is the no-arg constructor is
called, one of setSessionContext()/setEntityContext() is called and
finally ejbCreate() is called. The context given to bean at create time is
valid for its lifetime and is adjusted silently by the container during the
lifetime of the bean. This is why logically ejbCreate() is the constructor for
the bean. The javax.ejb.EJBContext interface looks like this.

public interface EJBContext {


public Principal getCallerPrincipal();
public EJBHome getEJBHome();
public boolean getRollbackOnly();
public UserTransaction getUserTransaction();
public boolean isCallerInRole(Principal p);
public boolean setRollbackOnly();
// Other deprecated methods
}

Copyright © 2001, DevelopMentor Inc. 163


Module 4: EJB Introduction

Deploying
Deployment technique similar but different for all containers

• Provide code bits plus deployment descriptor to container


• XML deployment descriptor held separately from bean code
• Contains EJB-specified settings under <ejb-jar>
• Vendor-specific settings elsewhere
• Container generates extra code and builds everything into deployable JAR
file

164 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

The deployment descriptor is held separately from bean implementation and


ties together the remote interface, the home interface and the bean class, and
defines attributes that specify the beans run-time requirements. The container
uses the descriptor at deployment time to generate code like the interposer,
EJB Home, stubs and skeletons.
It is tempting to think that it is possible to re-configure the bean without
changing the bean code. Sometimes this is not possible as the presence of an
attribute influences the code that has to be written. Even if it were possible,
care must be taken when changing the bean's deployment descriptor since
changes in the attributes will affect the run-time environment the bean
executes within. For example, a bean that assumes it is running as part of a
transaction may not work correctly if it is re-configured to run outside of a
transaction.
EJB 1.1+ deployment descriptors are in XML format and so are easily
generated and parsed. Figure 4.9 illustrates a minimal deployment descriptor
for a stateless session. Those settings that are defined by the EJB specification
reside under the <ejb-jar> top-level element. Many beans can be annotated
within a single descriptor. Some bean-related attributes (e.g. pooling
information) are defined by the container and not the EJB specification. These
cannot be under the <ejb-jar> element and must therefore be in another XML
file. A good (but counter-intuitive) example is the JNDI name of the beans
home.

<?xml version="1.0"?>
<ejb-jar>
...
<enterprise-beans>
<session>
...
<ejb-name>TellerSession</ejb-name>
<home>TellerSessionHome</home>
<remote>TellerSession</remote>
<ejb-class>TellerSessionBean</ejb-class>
<!--session-type is Stateful for stateful session-->
<session-type>Stateless</session-type>
...
</session>
...
</enterprise-beans>
<assembly-descriptor>
...
<assembly-descriptor>
</ejb-jar>
Figure 4.9: Minimal deployment descriptor (for a stateless session)

Copyright © 2001, DevelopMentor Inc. 165


Module 4: EJB Introduction

The exact details of the deployment process differ between EJB containers but
they all follow the same theme. A JAR file is created containing the remote
interface(s), the home interface(s), the bean class(es) and the deployment
descriptor(s). The deployment descriptor(s) may be generated by interacting
with the deployment tool. The next step is to deploy the JAR file and create a
new or extended JAR file that contains the container-generated code. This step
forces the container to bind the EJB Home into a JNDI context so it can be
discovered by the client.

166 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

Client view
Client performs JNDI lookup to obtain bean

• Server must already be running


• Server has bound EJB Home into JNDI context with name specified at
deployment time
• Client locates servers JNDI context and looks up reference to home
interface
• Client uses home interface to create/find bean and return reference to
remote interface
• Client uses remote interface to access bean

168 Copyright © 2001, DevelopMentor Inc.


Module 4: EJB Introduction

In order to run the client, the EJB container must already be running. Figure
4.10 shows a typical client usage pattern. The client must first perform a JNDI
lookup on the EJB Home for the bean in order to use its home interface. In
order to do this, it is necessary to link to the EJB servers JNDI context. This
example shows how to do this for the J2EE reference implementation. The
name to use in the JNDI lookup is the JNDI name specified at deployment time.
After obtaining the reference to the home interface it is a question of creating
the bean and getting back a reference to the remote interface. This can then
be used to access the bean.
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;
import javax.rmi.PortableRemoteObject;

...

Hashtable env = new Hashtable();


env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.cosnaming.CNCtxFactory");
env.put(Context.PROVIDER_URL,"iiop://server:1050");

Context ctx = new InitialContext(env);


Object o = ctx.lookup("TellerSession");
Class c = TellerSessionHome.class;
TellerSessionHome th =

(TellerSessionHome)PortableRemoteObject.narrow(o,c);
Teller t=th.create();
// ...
Figure 4.10: Client usage (of a stateless session)

Copyright © 2001, DevelopMentor Inc. 169


Module 4: EJB Introduction

Summary
• EJB is a sophisticated server-side runtime environment
• EJB container provides services through interception
• Interceptors built from declarative attributes specifying intent
• Caller accesses bean as standard RMI object
• Caller obtains home interface via JNDI and uses to create bean
• Caller accesses interposer, never underlying class

170 Copyright © 2001, DevelopMentor Inc.


Module 5

XML

Copyright © 2001, DevelopMentor Inc. 171


After completing this module, you should be able to:
 understand the XML Infoset
 have a basic understanding of how to program XML using SAX
 have a basic understanding of how to program XML using DOM
 have a basic understanding of XPath

172 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

Introduction To XML
XML has become the de facto format for
representing data and information for exchange
between software components and agents. The XML
Information Set (the Infoset) defines XML in the
abstract.

Copyright © 2001, DevelopMentor Inc. 173


Module 5: XML

What is XML?
XML is a data representation format for externalizing objects, values, and
information in general

• Abstract model (the XML Infoset) models XML-based information


• Concrete transfer syntax (XML1.0 + Namespaces) for transmitting and
storing XML-based information
• Type system provided by XML Schemas (XSD)
• XML is poised to replace previous communication/serialization protocols
used to integrate software components
• XML syntax is easy to master in an afternoon

174 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

XML is a technology for representing data and information. XML became a


World Wide Web Consortium (W3C) recommendation in 1998 and since then has
achieved nearly universal support from every vendor and development
platform. XML is rapidly becoming the software integration technology of
choice, filling the role once played by technologies such as Java RMI and
CORBA. By using XML to externalize objects and values, one can use XML as a
platform-neutral serialization/marshalling format, similar to the use of DCOM's
Network Data Representation (NDR) or CORBA's Common Data Representation
(CDR). By extension, XML information can be exchanged between systems as
the payload of a message-oriented (e.g., SMTP) or transaction-oriented
protocol (e.g., HTTP). In this respect, XML can act as an integration layer
between heterogeneous components and applications, much as RPC and
messaging protocols have been used in the past.
As shown in figure 5.1, XML typically exists at the "edges" of your component
or application, allowing a diverse range of programming environments to
integrate with your code. Because any programming technology can adapt to
XML, XML can be used as the "Esperanto" of cross-application and cross-
component information. Assuming one can externalize their internal objects
and values into an XML-based representation, these representations can be
transmitted to other applications that then can (hopefully) internalize them
into some native set of objects and values. The fact that the "sender" and the
"receiver" of the XML information may be built using radically different
technologies is hopefully masked by the use of a common XML-based format.

Lib1 Lib2 Lib3

XML Type System Internal Type System


Figure 5.1: Type segregation under XML

To allow consistent handling and processing of data, XML has a concrete


transfer syntax that is used to transmit and store XML-based information no
matter what system or technology generated the information. This transfer
syntax is known as XML 1.0 + Namespaces. The XML 1.0 + Namespaces transfer
syntax is a text-based format that can be mastered in an afternoon, especially
if one is already familiar with previous markup languages. The XML 1.0 +
Namespaces transfer syntax describes how to deal with character encodings,
whitespace, and CR/LF conversion, markup delimiters, and structural
validation. Fortunately, virtually any platform you are likely to program on has
a parser that can hide most if not all of these details.

Copyright © 2001, DevelopMentor Inc. 175


Module 5: XML

XML benefits from a layered design that encapsulates higher-layer


technologies and applications from the underlying byte-level representation of
XML information. XML has an abstract data model that all XML technologies are
designed around. This abstract model is called the XML Information Set (or
Infoset). The Infoset describes the entities and relationships of an XML
document in syntax-free terms. The relationship between the Infoset and XML
1.0 + Namespaces is shown in figure 5.2. Entire programming systems have
been created using only the Infoset (that is, no use of the XML 1.0 +
Namespaces transfer syntax is used). Additionally, most layered XML
specifications (e.g., XPath, XSLT, XML Schemas, SOAP) are defined solely in
terms of the Infoset. This allows new transfer syntaxes to be developed that
leverage the industry's existing investment in XML. It also allows in-memory
programming models to avoid the costly overhead of
serialization/deserialization to text.
Document: http://www.develop.com/roster.xml
Element: { xyzzy:abc, student }
Element: { null, name }
Characters: David Smith
XML Infoset
(Abstract Model)
Element: { null, age }
Characters: 38

<?xml version="1.0" encoding="UTF-16" ?>


<ns:student xmlns:ns="xyzzy:abc">
XML 1.0 + NS <name>David &#83;mith</name>
(Concrete Syntax) <age>38</age>
</ns:student>

Figure 5.2: The XML Infoset

By modeling the world in terms of the XML Infoset, one can build XML-based
architectures that are not dependent on the text-based transfer syntax of XML.
For example, consider the typical DBMS-centric approach to XML shown in
figure 5.3. In this scenario, the database exposes its information using the XML
1.0 + Namespaces transfer syntax. This requires an XML Parser to strip off the
markup delimiters and handle issues such as character set transformations and
whitespace mapping/stripping, which can take considerable system resources if

176 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

not done with care. In contrast, the approach illustrated in figure 5.4 uses the
native protocol of the database to extract the information, which invariably
will be more efficient, at least in terms of data transfer costs. However, to
enable the same XML-based processing code to work on the data, this scenario
maps the underlying data access technology (JDBC, OLE DB) to an XML infoset.
This can be done without streaming the data to the file system. Rather, the
XML adaptation code can simply map rows and columns to the methods that
represent XML-based elements in the chosen XML interface suite (SAX, DOM,
etc). Assuming that a streaming mode (e.g., firehose-mode cursor) data access
technique, the data access code will be highly performant. Additionally, if a
streaming mode XML interface suite is used (e.g., SAX), the entire database
result set may not need to be cached in memory at any one instant.

XML Parser

XML-based
XML

IIS
Processing
Software

Figure 5.3: Traditional DBMS/XML solution


WebRowset (or Equivalent)

XML-based
JDBC

Processing TDS (or equivalent)


Software

Figure 5.4: Just-in-time XML

Copyright © 2001, DevelopMentor Inc. 177


Module 5: XML

What is XML Schema?


XML Schemas are both an intrinsic type system for XML as well as a language
for expressing user-defined types

• Schemas bring civilization to XML


• Schema type system rich enough to handle most common type systems in
use
• Schema processors add reflection capabilities to the Infoset
• Schema compilers will eventually eliminate the need for low-level XML
coding
• Schemas based on representational polymorphism, not behavioral
• Schemas turn OO belief system upside down!

178 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The key to making XML truly useful to software developers is the XML Schema
language. The XML Schema language provides a type system over the structured
format of XML. If XML is considered "portable data", then XML Schemas should
be considered as "portable types", as the XML Schema language has been
embraced by virtually every major XML vendor organization. The XML Schema
specification became a proposed recommendation (PR) of the World Wide Web
Consortium (W3C) in March 2001. This version of the schema language is
identified by the http://www.w3.org/2001/XMLSchema namespace URI.
Previous versions of the specification are identified by namespace URI with
earlier years, and it is possible you may encounter software that has not been
updated to support the current specification.
Schema-aware processing software adds reflection-like capabilities to XML.
As shown in figure 5.5, the post-schema-validation (PSV) Infoset is adorned
with type information that makes every element and attribute's underlying type
name and definition available to software that consumes it. This allows
software to dynamically discover type information as the XML-based data is
consumed. Additionally, a schema-aware XML parser will validate that the
incoming text stream contains XML that adheres to the schema for the
corresponding namespaces found in the document. This ensures that only valid
information is processed by downstream components.

Copyright © 2001, DevelopMentor Inc. 179


Module 5: XML

Document: http://www.develop.com/roster.xml
{ xyzzy:abc, person } : { xyzzy:abc, student }
{ schema-ns, string } : { null, name }

Post-Schema string: David Smith


XML Infoset
(Abstract Model)
{ schema-ns, double } : { null, age }
double: 38.0

<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="xyzzy:abc"
targetNamespace="xyzzy:abc"
>
<xsd:complexType name="person" >
<xsd:sequence>
XML Schema <xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="xsd:double" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="student" type="tns:person" />
</xsd:schema>

Figure 5.5: Post-Schema XML Infoset

As shown in figure 5.6, XML schemas enable smart editors, code generation and
general-purpose validators. Additionally, by defining a mapping between the
XML type system and a programmatic type system, one typically gets the
[de]serialization of objects and values for free. This concept is illustrated in
figure 5.7. As the XML Schema language gains more momentum, more
programming environments will provide "schema compilers" that automatically
generate [de]serialization code based on XML Schema types, much as IDL
compilers do today for DCOM and CORBA-based systems.

180 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

Automatic
COM Type
Serialization
Information

JVM Type
Remote
Information
Method
Invocation

Directory
Smart
Type XML Schema Editors
Information

Code
DBMS Type Generation
Information

.NET Type General


Information Purpose
Validators

Figure 5.6: The role of XML Schemas

XML Instance
Objects and Values
Documents

XML Schema Type Programmatic Type

Figure 5.7: Bridging the XML type system

Copyright © 2001, DevelopMentor Inc. 181


Module 5: XML

'Programming' XML
Two Widely embraced APIs for programming XML

• SAX: Simple API for XML


• De facto standard: defined on xml-dev mailing list
• Event driven processor
• Models an XML document as a sequence of method calls on receiver
• DOM: Document Object Model
• "Official" API defined by W3C
• Processing based on "tree" containing typed nodes
• Other APIs possible (JDom, .NET)
• Java API for XML Processing--JAXP

182 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

There is nothing in the XML specification about how XML can be used in
programs, and there are many ways that XML could be parsed and manipulated.
However there are two mechanisms that have become standard, SAX and DOM.
SAX is an event-driven API, where a processor parses an XML document and
calls back to an application supplied interface when the processor finds
anything of interest. DOM models XML as a tree of nodes. Each node represents
different information items found in the XML document. Both mechanisms have
advantages and disadvantages, as will be discussed later.
There are other possible mechanisms: for example, Microsoft's .Net
architecture defines XMLReader and XMLWriter classes for reading and creating
XML, and Sun has accepted a JSR for a new API called JDOM (the Java DOM)
that offers more standard Java APIs for accessing XML.
On top of this Sun has defined JAXP, the Java API for XML. This provides a
standard way to create XML processors, something missing from the current
standards.

Copyright © 2001, DevelopMentor Inc. 183


Module 5: XML

Programming XML with SAX


The Simple API for XML is a de facto mechanism for
parsing XML documents. SAX defines an event-driven
parser that calls methods on an implementation of
the ContentHandler interface.

Copyright © 2001, DevelopMentor Inc. 185


Module 5: XML

SAX
SAX is a de facto standard interface suite XML

• Infoset projected onto handler interfaces


• "Sender" of document delivers information items piecemeal through
appropriate handler
• "Receiver" processes information as it arrives

186 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The Simple API for XML, SAX, is an event-driven mechanism for parsing XML
documents. SAX is not an official API, i.e. it is not designed or sanctioned by
the W3C. The original design process was set in motion by members of the xml-
dev mailing list led by Dave Megginson. In SAX, as the processor parses an XML
document it reports "interesting" events to a registered handler. These events
are things such as the start and end of the document, and the start and end
elements within the document. A SAX processor does not maintain context, so
that when it tells an application that it has just found an element, that
information is delivered in isolation. It is entirely up to the application to
maintain any state or context it needs.

Copyright © 2001, DevelopMentor Inc. 187


Module 5: XML

ContentHandler
Content handler models the core of the infoset

• Leaf nodes of Infoset delivered via a single method call


• Non-leaf nodes delivered via startXXX/endXXX methods
• Child nodes delivered between parent's startXXX/endXXX methods
• DefaultHandler implements ContentHandler (and others)

188 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The ContentHandler interface is the key interface in a SAX application. This


is the interface that is registered with a SAX processor to receive events about
the content of a document (such as the element information). The interface is
shown here in figure5.8. An application author is responsible for implementing
the methods on this interface. However, a helper class, DefaultHandler,
shown here in figure 5.9 provides a default implementation of this interface
and the other interfaces that a SAX application may need.
package org.xml.sax;
public interface ContentHandler {
void startDocument () throws SAXException;
void endDocument() throws SAXException;
void startElement(String namespaceURI, String localName,
String qName, Attributes atts);
void endElement(String namespaceURI, String localName,
String qName);
void startPrefixMapping(String prefix, String uri) ;
void endPrefixMapping(String prefix);
void characters(char ch[], int start, int length);
void ignorableWhitespace(char ch[], int start, int
length);
void processingInstruction(String target, String data);
void skippedEntity (String name);
void setDocumentLocator (Locator locator);
}
Figure 5.8: ContentHandler Interface

class DefaultHandler implements


ContentHandler,
DTDHandler,
EntityResolver,
ErrorHandler
{
...
}
Figure 5.9: DefaultHandler Class

The ContentHandler interface contains methods that are called by the


processor when it encounters various things within the document. The entire
parse is enclosed within calls to startDocument and endDocument. Each
element is reported via startElement and endElement methods, and the
text within an element in the characters method. Notice that the
startElement method takes namespace parameters and a reference to an
Attributes object. This contains the element's attributes (if it has any).

Copyright © 2001, DevelopMentor Inc. 189


Module 5: XML

Parsing a document
JAXP defines SAXParser[Factory] classes

• Different parsers define different parser classes


• All implement XMLReader
• JAXP abstracts differences away in SAXParser and SAXParserFactory

190 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

Many Java based parsers from different vendors support SAX. To support SAX
the parser must implement the XmlReader interface. Each vendor has a
different class that implements this interface. This means that to use a given
vendors parser the developer has to know which class to create. Worse than
that it means that it is not easy to swap parsers, for example another vendor
may offer better schema support, or simply have a quicker parser. To try and
get around this problem, Sun has defined the Java API for XML, or JAXP. This
defines a standard set of abstract classes that JAXP parsers provide. The
classes all live in the javax.xml.parsers package and offer a standard way
to create a parser.
The code in figure 5.10 shows how to create a SAX parser using JAXP. The
first two lines of code create a SAXParserFactory and use that to create a
SAXParser. The last line starts the parse in motion. The first parameter to
the parse method is an InputSource, which we will get to shortly. The
second parameter is an instance of a class that extends DefaultHandler, the
methods of this object will be called by the parser as the parse proceeds.
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();

parser.parse(new InputSource(xmlIn), new MyHandler());


Figure 5.10: Creating and Using a SAX Parser

And finally, figure 5.11 shows a partial simple implementation of a


ContentHandler. This simply emits the XML as its methods are invoked.

class MyHandler implements ContentHandler {


CharacterStream out;
public void startElement(String namespaceURI,
String localName, String rawName,
org.xml.sax.Attributes atts) {
out.write("<" + localName
+ " xmlns=\"" + namespaceURI + "\">");
}
public void endElement(String namespaceURI,
String localName, String rawName) {
out.write("</" + localName + ">");
}
// other ContentHandler methods elided for clarity
}
Figure 5.11: Simple Implementation of Content Handler

Copyright © 2001, DevelopMentor Inc. 191


Module 5: XML

InputSource
Abstracts away location of input XML

• Defined in SAX Packages


• Also used by DOM parsers
• Build InputSource on a stream or SystemId

192 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

One of the great things the SAX design group did was to define a standard way
of accessing an XML document. An XML document could come from many
places, for example, it could be a file on disk, or it could be a stream of data
coming over the Internet. The InputSource object allows us to abstract away
where the XML originates. An InputSource object can read XML from an input
stream of some sort, or from a URL (e.g. a file URL or an HTTP url). An
InputSource can be created by passing its constructor a
java.io.InputStream, a java.io.Reader or a java.lang.String. The
"string" (called the SystemId) is a URL that identifies the resource to be loaded,
this could be a file, or an HTTP URL.

Copyright © 2001, DevelopMentor Inc. 193


Module 5: XML

Programming XML with DOM


The Document Object Model is the "official" API for
XML. It is typically used when maintaining the tree
structure of XML is important

Copyright © 2001, DevelopMentor Inc. 195


Module 5: XML

DOM
DOM is a W3C interface suite

• Infoset projected onto typed node interfaces


• "Sender" of document implements node interfaces to support traversal
• "Receiver" has random access to the graph of nodes
• DOM is typically used when XML-ness needs to be retained

196 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The Document Object Model, or DOM, is the official W3C mechanism for parsing
XML documents. DOM Level 2 is currently a recommendation, while level 3 is
still a working draft. In the DOM, the XML document is represented as a tree
with the various parts of the XML document are exposed as nodes in the tree.
Each node is represented by an interface. A DOM maintains the structure of
parsed infoset, i.e. each node in the DOM has a context, so that it is easy to
reference a given nodes parent. For example, the parent-child relationships are
maintained within the DOM. This makes some types of processing (such as
XPath) much easier. DOM is generally less efficient than SAX. A DOM
implementation will typically use a SAX parser to build the DOM, and when a
complete document is parsed, the DOM can take up a large amount of memory.
However, there are benefits to using a DOM. DOM can be used to create XML
documents, and because a DOM maintains context it is possible to amend the
DOM. A typical DOM implementation will also provide well-formedness checks,
such that elements must be properly nested and the document can only contain
one root element.

Copyright © 2001, DevelopMentor Inc. 197


Module 5: XML

DOM logical structure


DOM logical structure == tree-oriented graph of nodes

• several node types that represent distinct information items


• several node interfaces implemented by node types
• For example Element and Document are nodes

198 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

A DOM represents the XML in a tree structure with each information item in the
XML document represented as a Node in the DOM. For example, XML elements
are represented by the Element node while XML attributes are represented as
an Attr node.
Figure 5.12 shows an example XML document projected onto a DOM. There
are several things to note here. The text inside an element
(<artist>Donatello<artist>) is represented as a Text node; this is a
child of the Element node, not the value of the element. Also note that
attributes are not children of elements. The Attr node is available through the
Element's getAttributeNodeNS method or the Node's getAttributes
method, not the Node's getFirstChild etc. methods. Finally, notice that
both processing instructions and comments are represented in the DOM, SAX
does not report comments.

Document
Attr

Text
P. Instruction Comment Element

Element Element Element


<?xml version="1.0"?>
<?order alpha ascending?>
<!-- renaissance art period --> Text Text Text
<period name="Renaissance">
<artist>Leonardo da Vinci</artist>
<artist>Michelangelo</artist>
<artist>Donatello</artist>
</period>

Figure 5.12: DOM logical structure example

Copyright © 2001, DevelopMentor Inc. 199


Module 5: XML

DOM Interfaces
DOM specification defines interfaces using the OMG's Interface Definition
Language (IDL)

• IDL is a programming language-neutral language for defining programmatic


types
• The DOM also defines two language mappings: Java and ECMAScript
(standard Javascript/JScript)
• Every DOM node implements at least two interfaces: a generic Node
interface and node-specific interface(s)

200 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The DOM interfaces are defined in the OMG's language independent, Interface
Definition Language (IDL). Java and ECMAScript mappings are also defined in
the core specification. The core interface in the DOM is the Node interface. All
the other interfaces extend this, as shown in figure 5.13's DOM hierarchy. Each
node is typed, i.e. there is no such thing as a Node node; instead the node will
be an Element or a Document. Each node type is identified by a constant, for
example the Element node's type is ELEMENT_NODE, the value of which is
defined to be "1"

Attr
Comment
CharacterData
Text
DocumentType

DocumentFragment CDATASection

Node Document

Element DOMException

Entity DOMImplementation

EntityReference NamedNodeMap

Notation NodeList

ProcessingInstruction

Figure 5.13: DOM Interface Hierarchy

Copyright © 2001, DevelopMentor Inc. 201


Module 5: XML

Node Interface
Node is the core interface of the DOM

• Can extract name and type of node


• Can extract value of node
• Can navigate [children] and [parent] of node
• Can downcast to strongly typed node-specific interface

202 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The Node interface (as shown in figure 5.14) is the core DOM interface. This
interface has methods for extracting the name, type and value of a node, so if
the current node is a ProcessingInstruction getNodeType returns
PROCESSING_INSTRUCTION_NODE (7), getNodeName returns the target of
the PI and getNodeValue returns the text of the PI, excluding the target.
Note that for some nodes getNodeValue returns null, this is true for Element
nodes, where you might expect getNodeValue to return the text between the
start and end elements, but this text is itself a child node.
public interface Node
{
Node appendChild(Node newChild)
Node cloneNode(boolean deep)
NamedNodeMap getAttributes()
NodeList getChildNodes()
Node getFirstChild()
Node getLastChild()
java.lang.String getLocalName()
java.lang.String getNamespaceURI()
Node getNextSibling()
java.lang.String getNodeName()
: : :
: : :
}
Figure 5.14: DOM Node Interface

Node also provides methods to navigate the DOM, including getChildNodes,


getFirstChild, getLastChild and getParent, methods to change the
value of a node, to remove children and to add children. However, the Node
interface doesn't provide a way to create nodes; that is the job of the
Document node.

Copyright © 2001, DevelopMentor Inc. 203


Module 5: XML

Document Interface
All nodes in a document must belong to that document

• Document interface has factory methods for each node type


• Cannot create from one document and insert into another
• DOMImplementation interface supports bootstrapping system (factory for
Document)

204 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The Document interface is the node that represents the entire XML document.
As can be seen in figure 5.15, the Document node contains factory methods for
creating other nodes (excluding other Document's). All nodes that are attached
to a Document must belong to that document. This means that it is not
possible to simple create two documents, and to use the Node.insertChild
method to insert nodes from one document into another. Instead, the
Document contains an ImportNode method that can be used.
public interface Document extends Node {
Attr createAttribute(java.lang.String name)
Attr createAttributeNS(java.lang.String namespaceURI,
java.lang.String qualifiedName)
CDATASection createCDATASection(java.lang.String data)
Comment createComment(java.lang.String data)
DocumentFragment createDocumentFragment()
Element createElement(java.lang.String tagName)
Element createElementNS(java.lang.String
namespaceURI,
java.lang.String qualifiedName)
EntityReference createEntityReference(java.lang.String
name)
ProcessingInstruction
// remaining methods elided for clarity
};
Figure 5.15: DOM Document Interface

The level 2 DOM does not define a standard way of creating documents, so
each parser has it's own method to create the initial DOM. Just like SAX,
however, JAXP does define a way to create a document. The code in figure
5.16 shows how to do this. Notice that the classes are
DocumentBuilderFactory and DocumentBuilder, and that to get a
Document interface it is necessary to call newDocument.

Copyright © 2001, DevelopMentor Inc. 205


Module 5: XML

<?xml version="1.0"?>
<p:period xmlns:p='urn:period:period-types name="Renaissance">
<artist>Leonardo da Vinci</artist>
<artist>Michelangelo</artist>
<artist>Donatello</artist>
</period>
Document emit(DOMImplementation di)
{
Document doc = di.createDocument(“p:period”,
“urn:period:period-types”,
null);
Attr a = doc.createAttribute("name");
a.setValue("Renaissance");
doc.getDocumentElement().setAttributeNode(a);
Element e = doc.createElementNS(“artist”, “”);
e.appendChild(doc.createTextNode(“Leonardo da Vinci”);
doc.appendChild(e);
e = doc.createElementNS(“artist”, “”);
e.appendChild(doc.createTextNode(“Michelangelo”);
doc.appendChild(e);
e = doc.createElementNS(“artist”, “”);
e.appendChild(doc.createTextNode(“Donatello”);
doc.appendChild(e);
return doc;
}

Figure 5.16: Example of DOM in Action

206 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

Using XPath
XPath is a W3C specification for addressing parts of
an XML document. An XPath expression consists of a
series of location steps.

Copyright © 2001, DevelopMentor Inc. 207


Module 5: XML

XPath
XPath is a uniform method for identifying portions of a document

• Syntax similar to file system paths


• "." means this directory
• "/" means root
• Documented in http://www.w3.org/TR/xpath
• Fundamental concept is location path

208 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

XPath can be used to "address" portions on an XML document. For example you
could retrieve all the elements in a given namespace, or all the elements by
name, or all the elements with an attribute called "Alice". It is called XPath
because the syntax is based on the syntax used to navigate file system paths in
both *nix and Windows. For example "." means the current node and "/" the
root node.
XPath is a W3C specification that models the XML document as a tree of
nodes.

Copyright © 2001, DevelopMentor Inc. 209


Module 5: XML

Location Path
A location path expression identifies a set of nodes in a document

• Absolute location paths begin at the root of the document and begin with a
forward slash "/"
• /child::guitar/child::model
• Relative location paths are relative to the current context node
• child::guitar/child::model
• Location paths can also be verbose or abbreviated
• /child::guitar/child::model == /guitar/model

210 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

The main concept in XPath is the location path. A location path is used to
identify a set of nodes within the XML document. There are two types of
location paths, absolute and relative. An absolute location path always starts
with a "/" and the match always starts at the root of the document. Relative
location paths start their match from the current "context" node. A location
path consists of one or more location steps, each step separated by a "/".

Copyright © 2001, DevelopMentor Inc. 211


Module 5: XML

Location Steps
Location paths consist of a sequence of one or more location steps

• Each step is separated by a forward slash "/" (composed from left to right)
• A location step has three parts: an axis identifier, a node test and zero or
more predicates
• XPath defines the following axes:
• child, descendant, parent, ancestor, following-sibling,
preceding-sibling, following, preceding, attribute,
namespace, self, descendant-or-self, ancestor-or-self
• A location path is evaluated left to right
• Resultant node set is passed to next location step

212 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

You can express location paths in one of two syntaxes, a fully qualified syntax
or an abbreviated syntax. The abbreviated syntax abbreviates some of the
more common uses of XPath, as we will see in a moment. A location step
written in the full syntax has three parts: an axis, a node test and zero or more
predicates. The axis determines which axis the match should search on. For
example "parent" says to search the parent node, and "attribute" to search the
attributes of the context node. In the abbreviated syntax the axis can be
omitted, in which case the axis defaults to the child axis. The node test
identifies the node to match. For example attribute::type looks for all
attributes of the context node with a name of "type". Finally, predicates are
used to filter the results of a location step.
Figure 5.17 shows an example of an XML document represented as a tree of
nodes, and an XPath location path. The location path consists of three location
steps. The first step says, "starting at the root, find any child elements that
have the name 'guitars'", as a document can only have one root element, this
step returns a node set containing one node.

/child::guitars/child::guitar/descendant::text()

root

guitars

guitar guitar

model model model model

text text text text


Les Paul Les Paul Tele Strat

Figure 5.17: Location Step Example

The second location step is a relative location step, and is evaluated relative to
all the nodes in the node set returned by the previous location step (in this
case only one node was returned). The location step says "find all 'guitar'
elements that are children of the context node". Remember that the first
location step returns a node set, each node in this set is made the context

Copyright © 2001, DevelopMentor Inc. 213


Module 5: XML

node, and then this location step is evaluated relative to that node. This
location step returns a node set containing two "guitar" nodes
The resultant node set is passed onto the final location step. Again each
node in the set in turn becomes the context node that the location step is
applied to. This returns all the text descendant nodes of the context node. We
finally end up with anode set consisting of four text nodes with the values, "Les
Paul", "Les Paul", "Tele" and "Strat".
Figure 5.18 shows an example location path, with a predicate
axis node test predicate

/child::guitars/child::guitar[@type=“Electric”]/child::model

initial location step location step location step

Figure 5.18: A Location Path

The first two parts are similar except that the second step now has a
predicate. The predicate is applied to the result of the location step up to this
point. The predicate filters the current node set. When a predicate is executed
it is evaluated against each node in the node set. The result of that evaluation
is either "true" or "false". If the predicate evaluates to "true" the node stays in
the node set, if it evaluates to false the node is removed. In this case, the
predicate looks for nodes that have an attribute ("@" is the abbreviated syntax
for attribute) called "type" whose value is "Electric", so <guitars><guitar
type='Electric'>Stratocastor</guitar></guitars> would remain in
the node set but <guitars><guitar
type='acoustic'>Taylor</guitar></guitars> would be omitted.
The resultant node set is passed onto the final location step, again each
node in the set in turn becomes the context node that the location step is
applied to, this simply returns any children of the context node who's elements
are called "model"

214 Copyright © 2001, DevelopMentor Inc.


Module 5: XML

Summary
• XML defines a serialization format and an abstract representation
• It is the abstract representation, the Infoset, that is important
• There are various APIs for manipulating XML
• DOM is a tree-based API
• SAX is an event-driven API
• XPath is a mechanism for addressing parts of a DOM

Copyright © 2001, DevelopMentor Inc. 215


Module 6

JDBC

Copyright © 2001, DevelopMentor Inc. 217


Java's predominant data access mechanism

After completing this module, you should be able to:


 understand why JDBC is used
 understand the JDBC Programming model
 understand how to optimize the use of JDBC

218 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

JNDI
JNDI is the Java Naming and Directory Service, a set
of Java interfaces and classes used to provide a
standard access mechanism to name and directory
servers. JNDI is used extensively in J2EE systems.

Copyright © 2001, DevelopMentor Inc. 219


Module 6: JDBC

Naming and Directory Services


Useful to store shared objects in managed repositories

• Naming service maps an object, such as a user or file, to a name


• Association between name and object is called a binding
• Once bound, an object can be located by name
• Related bindings form a context--may be hierarchical
• Contexts sharing same naming convention, operations called a naming
system
• Namespace is set of names bounded by naming system
• Directory service extends name service by storing additional attributes
• Attribute has name and one or many values
• Once bound, an object can be located by attributes

220 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

There are many different repository services where shared resources, or key
information about shared resources, can be stored so that they can be centrally
managed. Novell Directory Service (NDS) and Microsoft Active Directory are two
examples of such services and the Lightweight Directory Access Protocol (LDAP)
is an example of a protocol that might be used to talk to them. The common
theme to such repositories is that they provide name and directory services.
A naming service maps an object, such as a user, file, device, server,
network host, port etc, to a name. The association between the name and the
object it refers to is called a binding. Once bound, an object can be located
based on its name. A collection of related bindings is called a context and a
name in a context may bind to another context to form a hierarchy of contexts.
Figure 6.1 shows this. A naming system is an integral collection of related
contexts that all share the same naming convention, operations and
namespace, such as a filesystem, DNS or LDAP. If a name service contains an
object, then that object must conform to some serialization specification. This
is not always possible, so a name service can also contain a reference to an
object that essentially represents some kind of address.

“Root” context

“ThePrinter” <reference>
“FileServer” <reference>
“Raoul” <reference>
“Sanjay” <reference>
“Printers” context
“Printers” <reference>
“Employees” <reference> “Laser1” <reference>
“Color1” <reference>

binding
“Computers” context
“Homer” <reference>
“192.168.0.1” <reference>

Figure 6.1: Naming contexts

A directory service extends a naming service by allowing named objects to have


associated attributes that describe it. Attributes have a name and one or more
values. A directory service allows bound objects to be located by name or
attributes, and this allows content-based searching. Figure 6.2 illustrates this.
A directory service doesn't have to hold an object reference at all as it can
simply hold attributes that describe the object that can be used to recreate
the object when needed.

Copyright © 2001, DevelopMentor Inc. 221


Module 6: JDBC

“Employee” directory context

Name Raoul Name Sanjay


Badge No. 137497 Badge No. 009126
Job Title Hosist Job Title Middle Manager
E-mail raoul@ourmail E-mail sanjay@ourmail

Figure 6.2: A directory

222 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

JNDI architecture
JNDI provides service architecture for pluggable repositories

• Client uses same JNDI client API for any provider


• Client view largely independent of provider API or storage details
• JNDI is configurable so it's easier to write and deploy code
• Service provider conforms to service provider API (SPI)
• JDK 1.3 has LDAP, RMI registry, and CosNaming providers bundled
• Others (e.g. filesystem, Netware and NIS) can be downloaded)
• JNDI naming manager sits in the middle

224 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

There are many similar but different name/directory services. JNDI is a Java
API for naming/directory services operations, independent of a particular
implementation, and its storage mechanism and storage-specific APIs. The
developer is able to write code to the JNDI client API, regardless of the
underlying repository, and the deployer is able choose the actual repository
used at run-time. This makes code much easier to write and deploy.
JNDI also defines a service provider interface (SPI) that defines the Java
interfaces that a name/directory service provider must implement. The JNDI
naming manager uses this SPI to satisfy JNDI client requests. Figure 6.3
illustrates this. JDK 1.3 has LDAP, RMI registry, and CosNaming providers
bundled and other providers, such as those for the filesystem, Netware and
NIS, can be downloaded. This covers all common repositories but you could
write a service provider of your own if desired.

Client of JNDI API

javax.naming.*
JNDI API javax.naming.directory.*
javax.naming.spi.*
Naming Manager

Service Provider Interface


SPI Implementation

Figure 6.3: JNDI architecture

Copyright © 2001, DevelopMentor Inc. 225


Module 6: JDBC

The initial context


All JNDI operations relative to a context

• Bootstrap process--obtain Initial[Dir]Context


• Behaviour governed by properties
• Standard or service-, feature-, provider-specific
• java.naming.factory.initial and java.naming.provider.url
most important
• Can supply programmatically or declaratively
• System property, application resource file or provider resource file

226 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

All JNDI operations are relative to a JNDI context, modeled by the


javax.naming.Context interface for naming operations and the
javax.naming.DirContext for directory operations. To obtain the interface
that represents the "root" of the naming/directory service namespace, one
must instantiate one or the other of the javax.naming.InitialContext or
javax.naming.InitialDirContext concrete implementation classes.
Figure 6.4 shows the relationships.

javax.naming.Context

implements extends

javax.naming.directory.DirContext
javax.naming.InitialContext

extends implements

javax.naming.directory.InitialDirContext

Figure 6.4: JNDI interface/class diagram

To choose which actual provider is used and to configure that provider, the
code that creates the initial JNDI context must supply some properties, either
programmatically or declaratively. The most significant properties are
java.naming.factory.initial, which defines a factory for the initial
context within a particular service provider, and
java.naming.provider.url, which is used to configure the chosen service
provider. Figure 6.5 shows how to obtain a JNDI initial context by setting these
properties programmatically.
import javax.naming.*;
import java.util.*;

try {
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ladp.LdapCtxFactory");
env.setProperty(Context.PROVIDER_URL,
"ldap://localhost:389/o=developmentor, ou=java");
Context ctx = new InitialContext(env);
...
} catch (Naming Exception e) {
e.printStackTrace();
}
Figure 6.5: Obtaining initial context - programmatic properties

Copyright © 2001, DevelopMentor Inc. 227


Module 6: JDBC

Other properties can be set. Some are also standard, such as


java.naming.security.credentials, some are service-specific, such as
java.naming.ldap.version, some are feature-specific, such as
java.naming.security.sasl, and some are provider-specific, such as
com.sun.jndi.ldap.trace.ber.
Perhaps a better way of setting properties is declaratively, as shown in
figure 6.6. If a required property is not supplied programmatically in the
environment parameter, then the system properties will be checked followed
by any application resource files. An application resource file is a world
readable properties file with the name jndi.properties that must reside on
the classpath or be in the JAVA_HOME/lib directory. Note that all JNDI
properties can be set via an application resource file whereas only certain
standard JNDI properties can be set by using a system property (see the JNDI
documentation). It is also possible to customize a particular service provider by
using a provider resource file. This is a properties file with the name
[prefix/]jndiprovider.properties, so the provider resource file for the
com.sun.jndi.ldap.LdapCtx LDAP context would be
com/sun/jndi/ldap/jndiprovider.properties. There is at most one
provider resource file per service provider, and it is typically bundled with the
service provider and is loaded using the same class loader that loads the
service provider. JNDI only uses certain properties from this file and only for
certain operations (see the JNDI documentation).

# Application resource file (jndi.properties)


java.naming.factory.initial= com.sun.jndi.fscontext.RefFSContextFactory
java.naming.provider.url=file:/tmp

java
-Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory
-Djava.naming.provider.url=iiop:/localhost:1050 SomeJNDIApp

try {
Context ctx = new InitialContext();
...
} catch (Naming Exception e) {
e.printStackTrace();
}

Figure 6.6: Obtaining initial context - declarative properties

228 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

Data access with JDBC


Much of the data manipulated by web-services is in
databases. JDBC is Java's predominant data access
mechanism.

Copyright © 2001, DevelopMentor Inc. 229


Module 6: JDBC

What is JDBC?
Universal database access for Java

• Regardless of vendor
• Interface-based
• Provider implements interfaces (driver)
• Client chooses driver and uses interfaces
• Mandates SQL as command language
• Remember that any database API represents RPC for set-based operations

230 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

Data access APIs work much like an RPC protocol. The database client
establishes a database connection based on some endpoint information that
identifies at least the remote database server and the required data source.
This connection is used by the client to scope one or more set-based operations
against the underlying data. Each operation is represented by a request
messages encoded with details of one or more SQL statements and their input
parameters. The client sends the request message to the server down the
connection and blocks while the server processes it. Eventually the client
harvests the response message from the server, encoded with the result of the
operation and its output parameters (tabular results or a row count). Finally,
the client closes the connection and any resources associated with it. The key
thing to remember is that there is a movement of data across the network.
All DBMS systems provide proprietary mechanisms for performing I/O against
the database. JDBC is Java's universal data access strategy and as such it allows
data stored in different databases to be accessed using a common API. JDBC
defines a set of abstract interfaces. A database provider implements these
interfaces in a piece of code called a JDBC driver. The key interfaces must be
implemented by the driver, the others being optional. A database client
chooses an appropriate driver and uses the interfaces to access the underlying
database. Figure 6.7 shows the arrangement.

JDBC Application

JNDI JDBC DriverManager

MSSQL Driver Sybase Driver … Oracle Driver

Figure 6.7: JDBC driver model

JDBC mandates SQL as the data access command language, and thus has three
main problems to address. First, the mapping of SQL data types to host
language data types and SQL objects to host language objects. Next, there is
the impedance mismatch between SQL set-based processing and programming
languages record-at-a-time processing. Finally, host program flow must be
synchronized with SQL execution flow. The most obvious occurrence of this is
SQL error handling versus programming exceptions. Transaction support is also
required for a JDBC-compliant provider.

Copyright © 2001, DevelopMentor Inc. 231


Module 6: JDBC

Drivers are classified by database access style and Java purity. There are
four major categories of JDBC drivers. These are listed in figure 6.8. Type 1
JDBC drivers provide a simple bridge to a corresponding ODBC driver. This type
of driver was popular at the outset because it allowed existing ODBC drivers to
be leveraged. Because ODBC is a C-based API, the downside of these drivers is
that native code is required. The difference between type 2 and type 4 is that
type 2 uses native libraries and native calls and type 4 uses direct connections
and native protocols. For example, Oracle's type 2 driver uses OCI calls while
the type 4 driver uses sockets and Oracle's native TNS protocol.
Client Native Server Native
Type Meaning
Code? Code?
1 ODBC bridge driver yes no
2 Mix ‘n’ match yes maybe
3 Net driver no maybe
4 Pure Java driver no no

Figure 6.8: JDBC driver types

232 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

Programming JDBC
The JDBC programming model is interface based;
providers implement them and clients use them.
The challenge is to optimize the use of JDBC so that
data access is not a point of contention.

Copyright © 2001, DevelopMentor Inc. 233


Module 6: JDBC

JDBC programming model


JDBC defines interfaces implemented by private driver classes

• All JDBC objects are created by factories


• DataSource is a Connection factory
• Connection is physical connection to a data source and a Statement
factory
• Statement used to submit SQL action statements and queries and is a
ResultSet factory
• ResultSet is set of SELECT results or metadata
• SQLExceptions thrown and SQLWarnings exposed

234 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

The code in a JDBC driver is only accessible via JDBC interfaces. For instance, a
"JDBC Connection class" is a private class in the driver that implements the
java.sql.Connection interface. Every JDBC object (including the
Connection) is an instance of such a class and is created using the factory
pattern. A JDBC Connection class encapsulates a connection to a database. The
Connection class is a factory for the Statement classes (implementing a
derivative of java.sql.Statement). The Statement classes are used to
submit action statements or queries to the database. Statements can be
factories for sets of SQL results. The results can be manipulated with the
ResultSet class (implementing java.sql.ResultSet). A general overview of
the main JDBC classes is shown in figure 6.9.
class
interface
ResultSetMetaData

DriverManager (JDBC 1) Statement getMetaData()


DataSource (JDBC 2)
executeQuery()

createStatement() ResultSet
getConnection()

executeQuery()

PreparedStatement
Connection getXXX()

prepareStatement() setXXX()

getMetaData() DataTypes,
string int etc
prepareCall()
getXXX()
DatabaseMetaData
CallableStatement

Figure 6.9: JDBC programming model

Copyright © 2001, DevelopMentor Inc. 235


Module 6: JDBC

Connections
Connection interface represents physical database connection/client
session with the database

• Used to issue SQL statements


• Used for transaction management
• Used to obtain database metadata and driver capabilities
• Properties often encoded in jdbc URL
• Obtained via JDBC 1.0 DriverManger (deprecated)
• Obtained from JDBC 2.0 DataSource obtained via JNDI (preferred)
• Must be careful to close() aggressively

236 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

The JDBC Connection interface encapsulates a physical connection to a


database and represents a client session with a database. It is used to issue SQL
statements, to manage/take part in transactions, and provide access to
database meta data and schema.
There are two ways to open a connection. The JDBC
java.sql.DriverManager class can be used; all drivers support this method
and it is the most direct. In JDBC 2.0 and above, the preferred method is to use
a level of indirection through the DataSource family of interfaces, obtained
via a JNDI lookup. Whichever technique is used, once the client has located the
driver, the locater code gets out of way and the client deals directly with the
driver, as figure 6.10 from earlier shows.

JDBC Application

JNDI JDBC DriverManager

MSSQL Driver Sybase Driver … Oracle Driver

Figure 6.10: JDBC driver model

Each driver needs to be seeded with certain properties in order to supply a


connection. For example, the driver needs to know which database server to
talk to, the port on which that database server is listening and the exact
database instance to connect to. It may also need the credentials of a database
principal in order to sign-on to the database. There are a variety of ways that
the driver can be given this information, but the most common is the
connection URL string. The string has the format as shown in figure 6.11. Here
is an example of a connection string needed by NetDirect's JSQLConnect driver
used to talk to SQL Server -
jdbc:JSQLConnect://localhost:1433/database=mydatabase&user=
sa&pwd=.

Copyright © 2001, DevelopMentor Inc. 237


Module 6: JDBC

jdbc:<subprotocol>:<subname>

Always jdbc Driver name or Driver-specific


driver syntax to
connectivity identify source
mechanism
Figure 6.11: JDBC URL

The JDBC DriverManager.getConnection() method takes a connection


URL string and an optional user id and password (if not already encoded in the
URL). It passes the connection URL string to each registered driver in turn. The
first driver that recognizes and can use the string returns a connection. If no
drivers recognize the string, a "No suitable driver found"
java.sql.SQLException is thrown to the caller. A JDBC driver registers
with the DriverManager by calling DriverManager.registerDriver()
when the driver's class is loaded, as part of its static initialization. Often the
programmer loads the driver class explicitly by using Class.forName().
Figure 6.12 illustrates this. Alternatively, drivers can be implicitly registered by
listing them in the system property jdbc.Drivers. The DriverManager
loads all drivers in this list by calling Class.forName() on them.
DriverManager.getDrivers() will enumerate registered drivers. The
DriverManager class does not have to be instantiated, all of its methods are
static.
Connection con getConnection() {
// client loads the driver ...
Class.forName("com.jnetdirect.jsql.JSQLDriver");
// ... specifies the connection url ...
String url;

url="jdbc:JSQLConnect://localhost:1433/database=mydb&user=s
a&pwd=";
// ... and makes the connection
return DriverManager.getConnection(url);
}
Figure 6.12: Obtaining a JDBC Connection in the old world (deprecated)

JDBC 2.0 introduced the javax.sql.DataSource interface to provide a level


of indirection between the program and the JDBC driver and data source
properties selected. A driver vendor supplies DataSource classes that
implement the javax.sql.DataSource interface to be used by the

238 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

programmer. The DataSource class also implements setter methods (not a part
of the javax.sql.DataSource interface) that are used only by the
administrator. The only required property is the Description property. All
other properties are driver specific, but can include common properties like
serverName, portNumber, userID and password. The DataSource
properties are set by the administrator and the DataSource is bound to a
naming service or directory using JNDI. To this end, DataSource classes also
implement java.io.Serializable or javax.naming.Referenceable or
both. Figure 6.13 shows how to configure a DataSource class for the J2EE
reference implementation server and an example of setting up a DataSource in
code is shown in figure 6.14. By convention, if the naming service is
hierarchical, JDBC DataSources are bound in a jdbc sub context, for example,
jdbc/MyDS.
# Taken from J2EE reference implementation config file
jdbcXADataSource.1.name=jdbc/MyDS
jdbcXADataSource.1.classname=com.jnetdirect.jsql.JSQLXAData
Source
jdbcXADataSource.1.dbuser=sa
jdbcXADataSource.1.dbpassword=
jdbcXADataSource.1.prop.serverName=localhost
jdbcXADataSource.1.prop.portNumber=1433
jdbcXADataSource.1.prop.databaseName=mydb
Figure 6.13: Example server DataSource configuration

// This is what the J2EE server does


public static void registerDS()
{
com.jnetdirect.jsql.JSQLXADataSource ds =
new com.jnetdirect.jsql.JSQLXADataSource();
ds.setUserID("sa");
ds.setPassword("");
ds.setServerName("localhost");
ds.setPortNumber("1433");
ds.setDatabaseName("mydb");
Context ctx = new InitialContext();
ctx.bind("jdbc/MyDS");
}
Figure 6.14: Example of how to register a DataSource

To use a DataSource object, the programmer obtains a JNDI


javax.naming.InitialContext and does a Context.lookup() using the
name used to bind the DataSource. The instance retrieved must be cast to the
javax.sql.DataSource interface. Since all vendor DataSources must
implement this interface, the remaining code is driver independent.
DataSource.getConnection() is then used to obtain a JDBC connection.

Copyright © 2001, DevelopMentor Inc. 239


Module 6: JDBC

This is shown in figure 6.15. Since the driver name and configuration
parameters are abstracted behind a symbolic name stored in a directory or
name service, they can be changed by the administrator without changing a
single line of code in any application.
Connection getConnection() {
// client gets server JNDI context ...
Context ctx = new InitialContext();
// ... specifies the JNDI name ...
DataSource ds = (DataSource)ctx.lookup("jdbc/MyDS");
// ... and makes the connection
return ds.getConnection();
}
Figure 6.15: Obtaining a JDBC Connection in the new world

Once a connection has been established, capabilities of the driver and


information about the database can be obtained through the
DatabaseMetaData interface returned from
Connection.getDatabaseMetaData(). When writing a generic application,
it is a good idea to determine if functionality is supported before attempting to
use it. The most useful information obtained through DatabaseMetaData is
information about database objects. A series of methods produce lists of
descriptive attributes. For example, DatabaseMetaData.getTables()
produces a ResultSet of tables available in the database. Columns contain
the information items roughly corresponding to the items in the SQL-99
Information schema.
Since a database connection and other database resources are precious
resources, non-deterministic garbage collection will be sub-optimal. Calling
Connection.close() closes the connection or releases it to the connection
pool. Calling Connection.close() is supposed to release all the other
resources that the connection holds, but due to differences in driver
implementation, all resources should be closed explicitly before closing the
connection.
Many methods of JDBC interfaces throw a java.sql.SQLException
containing a descriptive error message, the SQL state as defined by SQL-CLI and
an optional, vendor-specific error code. Since complex operations can produce
more than one error, SQLException.getNextException() can be used to
walk through multiple errors. The java.sql.SQLWarning class provides
database "warning level" information. Since warnings are not fatal errors, they
are not thrown as exceptions and must be explicitly requested. For instance,
warnings on a connection are available by calling
Connection.getWarning().

240 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

Simple statements
Statement executes ad hoc, non-parameterized SQL

• Connection.createStatement() creates
• Statement.executeQuery() for query yielding single ResultSet
• Statement.executeUpdate() for action yielding single record count
• Statement.execute() for either or multiple results

242 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

The Statement interface allows simple non-parameterized statements to be


executed. A Statement is created by Connection.createStatement().
Once created, a Statement can be used to execute ad hoc SQL statements.
Statements can return record counts, ResultSets or both when executed. If
you know that a Statement returns only one ResultSet, the
executeQuery() method is used. If you know that a Statement returns only
one record count, the executeUpdate() method is used. If you do not know
whether a record count or ResultSet will be produced, use the generic
execute(). This method returns a boolean that indicates if the result is a
ResultSet or record count. The Statement.getUpdateCount() or
Statement.getResultSet() methods can then be used as appropriate. An
example of creating and using a simple Statement is shown in figure 6.16.
String str = "SELECT FIRST_NAME, LAST_NAME FROM EMPLOYEE";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(str);

// Or...

String str = "UPDATE EMPLOYEE SET LAST_NAME='Posters'


WHERE FIRST_NAME='Bill'";
Statement stmt = conn.createStatement();
int count = stmt.executeUpdate(str);
Figure 6.16: Obtaining and using a JDBC Statement

Copyright © 2001, DevelopMentor Inc. 243


Module 6: JDBC

Results
ResultSet models query result as tabular data

• Returned from Statement.execute()/Statement.executeQuery()


• Returned from some DatabaseMetaData methods
• Maintains a "row-at-a-time" cursor
• Fire hose cursor is default, JDBC 2.0 allows others
• Column values obtained from current row using typed getters
• Column metadata available from ResultSetMetaData
• ResultSet scoped by Statement that produced it

244 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

The ResultSet interface models the result of a query as tabular data. One or
more ResultSets may be returned from Statement.execute() and
Statement.executeQuery(). ResultSets of database schema information
are also returned from some DatabaseMetaData methods. A ResultSet
maintains a cursor indicating the current row. You can move sequentially
through a ResultSet with the next() method, which returns one row of data
at a time. There is no bulk fetch facility. The ResultSet cursor is initially
positioned before the first row, so next() must be called to obtain the first
row. The Statement scopes any ResultSets it has produced so if the
Statement is closed then the results are lost.
Column values from the current row are returned using typed getters. Either
one-based ordinals or column names may be used. For instance, to retrieve a
column value known to be of type boolean, either the getBoolean(int
colIndex) or getBoolean(String colName) methods could be used. In
general, it is always safest to use the correct mapping of SQL types to Java
types. The mapping of SQL types to Java types is defined by the JDBC
specification. Getters (and setters) can perform a type conversion if this is
supported by the driver. There is a standard set of type conversions that all
drivers must support. If the type specified is incorrect or the driver does not
support the conversion, a SQLException is thrown. Driver writers can extend
the set of supported types by deriving from Statement and/or ResultSet
and adding special getters and setters. An example of this is Oracle's support of
CURSOR and ROWID data types.
Walking through a ResultSet and pulling out column value is illustrated in
figure 6.17. When getting column values, remember that the JDBC
specification only requires column values to be available in ordinal order and to
be read only once. Most drivers will allow access in any order, but the
"reference" driver (the Sun ODBC bridge) is a notable exception.

Copyright © 2001, DevelopMentor Inc. 245


Module 6: JDBC

try {
Connection conn = getConnection();
Statement stmt = conn.createStatement();
String sql = "SELECT * FROM EMPLOYEE WHERE LAST_NAME =
'Smith'";
ResultSet rs = stmt.excuteQuery(sql);
while (rs.next()) {
System.out.println ( "Customer id:"+rs.getInt("ID")+"
found");
System.out.println ( "First
Name:"+rs.getString("FIRST_NAME"));
System.out.println (
"Address:"+rs.getString("ADDRESS"));
}
}
catch (SQLException e) { e.printStackTrace(); }
finally {
try { if (stmt!=null) stmt.close(); if (conn!=null)
conn.close(); }
catch (SQLException e) {e.printStackTrace()}
}
Figure 6.17: Using a JDBC ResultSet

NULL values are handled specially. If you think the value of the field may be
NULL, it is required to use an object type or the generic getter, getObject().
Retrieving a NULL value with getObject() will not necessarily return a NULL
object. After retrieving the value, wasNull() should be called to determine if
the value was NULL. Here is an example of how to deal with a possible NULL
field value.
Object o = rs.getObject(1);
// Object could be an integer with value 0
if (rs.wasNull())
System.out.println("[NULL]");
else
System.out.println(toString(o));

Information about the ResultSet is available through the


ResultSetMetaData interface that allows you to get basic information about
number and type of columns, as well as extended information, such as
precision and scale for fixed decimal columns. In JDBC 3.0, there is a standard
way to retrieve auto-generated key column (identity column) values, using
Statement.getGeneratedKeys().

246 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

The default ResultSet maintains a forward-only and read-only cursor. In


fact, JDBC 1.0 only supported this cursor type. JDBC 2.0 defines different types
of cursor behaviour (scrollable, sensitive to changes and updateable) and these
can be specified when creating the Statement. These behaviours are usually
accomplished by using cursors inside the database.

Copyright © 2001, DevelopMentor Inc. 247


Module 6: JDBC

More complex statements and results


For executing stored procedures and batch SQL

• CallableStatement isa PreparedStatement isa Statement


• PreparedStatement: pre-compiled, parameterized statements with in
params
• CallableStatement: out params
• Parameters specified using 1-based ordinals
• In params set by PreparedStatement typed setters
• Out params registered by
CallableStatement.registerOutParameter()
• Execution format: {? = call procedure_name(?, ?)}
• Out params reaped by CallableStatement typed getters
• Complex sprocs may produce multiple results

248 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

The three Statement interfaces differ only in the degree of parameter


support. Statement allows simple ad hoc, non-parameterized statements to
be executed. PreparedStatement extends Statement and provides support
for pre-compiled, parameterized statements with input parameters.
CallableStatement extends PreparedStatement and adds support for
obtaining output parameters from functions and stored procedures. Each
Statement type is created by a separate factory method on the Connection
interface, prepareStatement() for a PreparedStatement and
prepareCall() for a CallableStatement. Because PreparedStatement
and CallableStatement represent pre-compiled, parameterized statements,
the SQL statement is passed as a parameter to their factory methods.
One way to design a client-server or three-tier system for fewest round trips
to the database is to analyze the system down to use-cases. Each use-case is
then coded into a single stored procedure inside the database meaning that
each use-case requires only a single database round trip. A single stored
procedure can be arbitrarily complex, executing many statements. Because a
stored procedure is pre-compiled (the preparation of the execution plan is
separate to the execution itself) then it can be parameterized (having multiple
inputs and/or multiple outputs) and should prove quicker to execute. Stored
procedure dialects change between databases. An example of how to create a
simple stored procedure within a SQL Server database is shown in figure 6.18.
CREATE PROCEDURE sp_update_employee
@first_name VARCHAR(32),
@last_name VARCHAR(32)
AS
UPDATE EMPLOYEE SET LAST_NAME=@last_name
WHERE FIRST_NAME=@first_name
Figure 6.18: A simple stored procedure

Figure 6.19 shows how to use a CallableStatement to execute this stored


procedure with input parameters. JDBC invokes stored procedures in a
database neutral way using the XOpen escape clause format ({? = call
procedure_name(?, ?)}). Most drivers will also let you use the database-
specific syntax. The "?" character is the placeholder for a parameter or return
value. When using a parameterized statement, parameters are always specified
by using one-based ordinals, based on the position of the parameter. The typed
setter methods inherited from PreparedStatement are used to specify the
values of input parameters. NULL values set be set into parameters by using
setNull().

Copyright © 2001, DevelopMentor Inc. 249


Module 6: JDBC

String str = "{call sp_update_employee(?,?)}";


CallableStatement stmt = conn.prepareCall(str);
stmt.setString(1, "Bill");
stmt.setString(2, "Posters");
stmt.execute ();
Figure 6.19: Calling a stored procedure passing input parameters

When using CallableStatement to execute a stored procedure with output


parameters, their types must be registered before the call, using
registerOutParameter(), as shown in figure 6.20. The output parameters
can then be harvested after the call using the typed getters of
CallableStatement. JDBC 3.0 provides a method on the CallableStatement
to allow getting information about the number, type, and direction of
parameters in a stored procedure.
String str = "{call sp_get_employee_fname(?,?)}";
CallableStatement stmt = conn.prepareCall(str);
stmt.setInt(1, 1003);
stmt.registerOutParameter(2,Types.VARCHAR);
stmt.execute();
String fname = stmt.getString(2);
Figure 6.20: Calling a stored procedure harvesting output parameters

A stored procedure (or indeed any batch of SQL commands) may be complex
enough to produce multiple results containing both record counts and
ResultSets, in which case the generic execute() is used. Figure 6.21 shows
how to deal with multiple results.
String str = "{call DO_COMPLICATED_STUFF()}";
...
stmt.execute();
while(true) {
if(stmt.getUpdateCount() > 0) { // an update count
stmt.getMoreResults();
continue;
}
if((rs = stmt.getResultSet()) != null) { // a result set
stmt.getMoreResults();
continue;
}
break;
}
Figure 6.21: Handling multiple results

250 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

Extending ResultSets
ResultSet not designed with n-tier architectures in mind

• Not remoteable or serializable


• JDBC 2.0 Rowset extends ResultSet
• Wraps up and layers services over ResultSet or other tabular data
• Is a JavaBean
• Anyone can write
• Sun provides disconnected RowSet and XML RowSet

252 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

ResultSets are not remoteable and they do not provide serialization support,
so they can't be passed back by reference or by value from the middle tier to a
base client. They do not support disconnected operation as a database
Connection and Statement must be kept open for a ResultSet to be valid.
In short, they were never designed with n-tier architectures in mind. JDBC 2.0
defines the javax.sql.Rowset interface as an extension of the ResultSet
interface. A Rowset object implement the javax.sql.Rowset interface and
provides a wrapper around, and an extension of, a set of rows from a
ResultSet or some other source of tabular data, e.g. a file or spreadsheet. A
Rowset can be implemented by anyone on top of existing JDBC APIs.
Primarily, a Rowset has two purposes. First, the RowSet interface adds
support for the JavaBeans component model by providing getters and setters
for all of the JDBC properties related to the underlying data (e.g.
setDataSourceName()/getDataSourceName()), a simpler high-level interface to
executing SQL statements and retrieving data and support for JavaBeans
events, allowing other components in an application to be notified when an
important event on a rowset occurs, such as a change in its value. This allows a
Rowset object to be used in a visual JavaBean development environment where
it is created and configured at design time and executed at runtime. Second, a
Rowset can be used to layer extra services on top of a ResultSet. For
instance, implementing cursor types not supported by the underlying JDBC
driver (such as disconnected ResultSets) or making it easier to send tabular
data over a network (serializing data as XML).
Sun provides some Rowset implementations that are currently in the "early
adopter" phase. The CachedRowSet implementation represents a
disconnected set of rows that are being cached outside of a data source, much
like the ADO disconnected RecordSet. It is serializable so it can easily be sent
across the wire. An example of how to use the CachedRowSet is given in
figure 6.22. The WebRowSet extends the CachedRowSet and uses XML as its
serialization format. Figure 6.23 shows how it can be used. Because
WebRowSet is a CachedRowSet it can also be populated from an existing
ResultSet. Because the WebRowSet and the CachedRowSet reveal the
database schema to the base client, it might be preferable to walk over the
ResultSet and build your own XML adhering to some database-neutral XML
schema.

Copyright © 2001, DevelopMentor Inc. 253


Module 6: JDBC

ResultSet rs = stmt.excuteQuery();
CachedRowSet crs = new CachedRowSet();
crs.populate(rs);
smt.close();
con.close(); // now we are disconnected
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("data.file"));
oos.writeObject(crs);
...

// in some other place, at some later date


...
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("data.file"));
CachedRowset crs = (CachedRowset)ois.readObject();
while (crs.next()) {
System.out.println ( "Customer id:"+crs.getInt("ID")+"
found");
System.out.println ( "First
Name:"+crs.getString("FIRST_NAME"));
System.out.println (
"Address:"+crs.getString("ADDRESS"));
System.out.println ( "Age:"+crs.getInt("AGE"));
}
Figure 6.22: Using a CachedRowset

wrs = new WebRowSet();


wrs.setURL("jdbc:odbc:SomeDS");
wrs.setCommand("select * from mytable");
wrs.execute(); // populate and disconnect

java.io.FileWriter writer = new


java.io.FileWriter("file.xml");

wrs.writeXml(writer); // persist as XML


Figure 6.23: Using a WebRowset

254 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

Optimizations
Remote data access means round-trips

• Round-trips adversely affect performance scalability


• Round-trips must be minimized
• Use appropriate cursor type
• Use stored procedures
• Use batching techniques
• Don't pull data to middle-tier unless it is for the client or will be cached

256 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

A single middle-tier operation may access the database many times. Very often
data access must take place under a transaction to maintain correctness. As
the operation progresses each data access will take some locks on the data (for
which there is contention). As mentioned previously, remote data access means
at least one round-trip for every statement executed. Round-trips are
expensive and may unnecessarily extend the lifetime of the operation. The
longer the operation lasts, the longer locks are held. The longer locks are held,
the more contention there is in the system. In a highly concurrent system
contention is the enemy of performance and scalability.
A ResultSet has an associated cursor used to traverse and manipulate the
results. JDBC 1 only offered one type of cursor--forward only, read only. The
data returned has to be processed in order, cannot be updated and is not
sensitive to changes by others. JDBC 2 offers a richer set of cursors that allow
the data to be read in any order, updated in-place and sensitive to changes by
others. None of these newer cursor types is really appropriate for the middle-
tier as they either cause too many round-trips or hold too many locks in the
database.
A good general rule of thumb is to avoid dragging data back from the
database to the middle-tier unless it will be given back to the client or is to be
cached. In particular, don't pull data back from the database, update it and
then put it back in the database again in the same middle-tier operation.
Prefer using a stored procedure to minimise round-trips.
In general, taking the part of a middle-tier operation that accesses the
database and running it as a stored procedure in the databases will minimize
round-trips. Many developers are loathe to do this as it reduces the portability
of the systems because stored procedure syntax and operation varies from one
database to another.
Stored procedures may not be an option. Also, stored procedures may need
to be composed together into a larger operation but the developer has no
database administrator rights to add another stored procedure to do this (or
cannot convince the db admin to do it). In these cases it makes sense to batch
SQL statements together and present them to the database in one round-trip.
Figure 6.24 shows how two stored procedures can be called from the middle-
tier in one round trip instead of the usual two.

Copyright © 2001, DevelopMentor Inc. 257


Module 6: JDBC

// Update batching
con.setAutoCommit(false);
stmt.addBatch("insert into emp values(1, 'Joe')");
stmt.addBatch("insert into emp values(2, 'Charlie')");
int[] updCount = stmt.executeBatch();

// Batching any SQL


String str = "declare @n integer";
str += ";exec sp_get @n output";
str += ";select @n";
str += ";exec sp_put @n+1";
stmt.execute(str);
int ret = stmt.getInt(1);
Figure 6.24: Batching techniques

258 Copyright © 2001, DevelopMentor Inc.


Module 6: JDBC

Summary
• JDBC is an interface-based specification for universal data access
• Used by clients, implemented by database providers (drivers)
• Simple interface model: Connections, Statements and ResultSets
• SQL is the command language
• Data access implies round trips--work hard to minimize them

Copyright © 2001, DevelopMentor Inc. 259


Module 7

Transactions

Copyright © 2001, DevelopMentor Inc. 261


Keeping data safe in the face of concurrency

After completing this module, you should be able to:


 understand how transactions are used to protect data
 learn the importance of balancing speed with correctness
 appreciate the difference between local and distributed transactions

262 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

Transactions
Transactions allow us to keep shared, read-write
data safe in the face of concurrent access.
Understanding how transactions affect the
performance and scalability of your system is key to
success.

Copyright © 2001, DevelopMentor Inc. 263


Module 7: Transactions

Data access challenges


Keep data consistent despite concurrency and failure

• Isolate client operations from each other


• But execute efficiently and scale
• Handle partial failure
• Present a simple programming model

264 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

Keeping sensitive data consistent is quite a challenge. The main two problems
are those of concurrency and failure.
Web services may have to deal with many concurrent clients. Much of the
data maintained and manipulated by such a web service is shared and read-
write in nature. This data must remain consistent in the face of concurrent
access. For instance, we cannot have one client reading a particular piece of
data whilst another is halfway through writing to it. Isolating the effects of one
client's actions from those of another is one of the keys to providing
consistency of data. Naive isolation techniques will not work however.
Traditional exclusive locks are not enough. Both read locks (shared locks)
and write locks (exclusive) locks are needed in tandem to protected data
efficiently. Traditional well-formed locks (where the lock is released straight
after the protected data is accessed) are not enough either. Data may need
locking for extended periods of time to remain consistent within an operation
otherwise common problems can occur, such as "lost updates", "dirty reads",
"unrepeatable reads" and "phantom reads". A "lost update" is where your
changes are overwritten by another operation before you can finish. A "dirty
read" is where you read data that is being changed by another operation that
has not yet completed. An "unrepeatable read" is where the data changes while
you are looking at it because another operation changed the data and ran to
completion in between you looking at it once and then looking at it again. A
"phantom read" is where data gets added/deleted while you are looking at it
because another operation added some data and ran to completion in between
you looking at it once and then looking at it again. However isolating whole
operations will not work because it is too coarse-grained and provides too much
contention. This kills performance and scalability. Some compromise is needed.
The key is that each operation must appear to be serialized even though, for
performance sake, operations must be allowed to execute in parallel wherever
possible.
Applications and systems occasionally fail--distributed systems especially
have many possible weird failure modes. Data must remain consistent in the
face of such failure. Operations must not fail halfway through and leave
inconsistent data for others to see--they must either completely succeed or
completely fail. To make recovery from failure possible both the data and all
changes made to the data during an operation must be durably stored so that
neither is lost.
The many lines of complex code needed to keep data consistent generally
follow a set pattern that is orthogonal to the problem domain. For this reason
the system (operating system, application server, database etc) often provides
most of the plumbing code necessary to implement the safety features, leaving
the developer a relatively simple interface to program against.

Copyright © 2001, DevelopMentor Inc. 265


Module 7: Transactions

Transaction basics
ACID properties guaranteed

• Simple agent API: commit or abort


• Resource Managers (RMs) manage data
• Transaction Managers (TMs) coordinate parties

266 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

A transaction protects the data manipulated by a sensitive operation with its


ACID properties. The "A" means that a transacted operation is atomic--it
completely succeeds or completely fails. Any data it manipulates assumes a
new consistent state upon successful method end (transaction commits) or
remains at the initial valid state upon method failure (transaction aborts). The
"C" means consistency, which is the ultimate goal here. The point is that the
transaction will maintain data consistency (via "A","I" and "D") according to the
rules set down by the developer. It is still up to the developer to ensure that
logical consistency problems are not introduced via erroneous code, badly
designed database tables etc. The "I" stand for isolation. Fully isolated
transactions guarantee that all concurrent transactions will interact only in
ways that produce the same effect as if each transaction were entirely
executed one after the other, so "dirty reads", "non-repeatable reads", and
"phantom reads" are not possible. The "D" means that the data and all changes
to it are durably stored so they do not get lost in case of failure.
There are two kinds of transaction: local and global. Local transactions are
used when all the data is in one place (such as a single database) and global (or
distributed) transactions are used when disjoint data is spread around the
network in different places (such as multiple databases, message stores, file
systems etc). Local transactions have a simpler model than distributed
transactions but as the local transaction model is just a degenerate case of the
distributed transaction model then the distributed transaction model is
explained here.
The responsibilities of providing a transacted operation are divided up
between a number of co-operating parties. The "agent" is the code that would
like to execute an operation under the protection of a transaction. The
Transaction Manager (TM) is part of the system and is responsible for the
details of starting and stopping a transaction and coordinating all other parties
involved in the transaction. A Resource Manager (RM) knows how to manipulate
a persistent shared resource according to the ACID properties of a transaction.
An example of an RM might be a database such as DB2 or Oracle. The agent
asks the TM to start a transaction on its behalf and gets back some abstraction
of the transaction that allows the agent to programmatically commit or abort
the transaction at any time. The agent then acquires the resources needed by
the operation from a selection of RMs. The agent asks the TM to associate each
resource with the transaction and the TM, in turn, instructs each RM of the
association. Now the agent is in a position to manipulate the resources under
the control of the transaction, safe in the knowledge that each RM will durably
log each change against the transaction and provide the correct isolation
between it and other transactions. Finally, the agent will make a decision
whether to commit the changes made or abort them. The TM will propagate
the agents wish to all RMs involved in the transaction and coordinate the
process of allowing them to publish or discard the changes, reporting the
outcome back to the agent. Note that the agent is the only party that is in
control of the "big picture" and therefore is the only party that can commit the

Copyright © 2001, DevelopMentor Inc. 267


Module 7: Transactions

transaction. Any other party in the transaction (i.e. the TM or any of the RMs)
may abort the transaction at any time.

268 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

Local transactions
Simple model : single agent, single RM

• Transaction implicitly associated with/scoped by resource


• No need for external TM
• Each technology has own local transaction API (e.g. JDBC, JMS etc)
• JDBC Connection scopes local transactions
• DatabaseMetaData.supportsTransactions() to tell if supported
• By default, each statement executes in own transaction which auto-
commits
• Connection.setAutoCommit(false) allows multi-statement
transactions
• Must manually Connection.commit() or Connection.rollback()

270 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

A local transaction can only be used when all the data being manipulated is
held within a single RM. Because a local transaction only involves a single agent
and a single RM there is no need for an external TM as there are no other
parties to coordinate. The TM is actually part of the RM in this case. Figure 7.1
illustrates.

1. Acquire transacted resource

2. Use transacted resource


Resource
Manager
Agent 3. Commit (or abort) transacted (with own
resource internal
Transaction
4. OK (or not)
Manager)

Figure 7.1: Local (single party) transactions

Very often a local transaction is implicitly tied to the resource acquired from
the RM. For instance, a local database transaction is associated with, and
scoped by, a database connection. It can be started with BEGIN
TRANSACTION and ended with COMMIT or ROLLBACK. The stored procedure in
figure 7.2 shows how.
CREATE PROCEDURE transfer
@id integer,
@amount integer
AS
BEGIN TRANSACTION
update savings set amount = amount+@amount where id=@id
update checking set amount = amount-@amount where id=@id
COMMIT
}
Figure 7.2: SQL local transactions

There is no standard Java programming interface for local transactions. In


JDBC, local transactions are associated with, and scoped by, a Connection
object. You can find out if local transactions are supported by using the
Connection.getMetaData().supportsTransactions() method. A JDBC
client that wants local transactions does not typically execute BEGIN
TRANSACTION and COMMIT/ROLLBACK commands but instead uses JDBC's
implicit transaction model. The Connection has an "auto-commit" mode that
is on by default. This means that each SQL statement issued is in a transaction
and the transaction commits (or aborts) at the end of the statement execution.

Copyright © 2001, DevelopMentor Inc. 271


Module 7: Transactions

This is true whether single statements or batches are used. Turning auto-
commit mode off means that the execution of multiple statements can be
composed into the same transaction. The execution of the first statement in
the group causes the transaction to start and the transaction must be ended
manually with Connection.commit() or Connection.rollback(). Figure
7.3 shows how to do this. This effectively provides "chained transactions"
where the database starts a new transaction when the preceding one finishes.
try {
Connection con = getConnection();
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.executeUpdate(
"update savings set amount=amount+10 where id=1000");
stmt.executeUpdate(
"update checking set amount=amount-10 where id=1000");
con.commit();
catch (...) {
con.rollback();
}
Figure 7.3: JDBC local transactions

It is considered good practice to handle any exceptions that may occur in the
data access code and manually roll back the transaction if desired, rather than
relying on any default behaviour of the driver.

272 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

Transaction tensions
Transactions require isolation, isolation causes contention

• Contention hurts performance


• Contention hurts scalability
• Lock as little data as possible for as short a time as possible
• Only use TX when necessary, preferring local over global
• Use lowest isolation level possible
• Keep transaction time down

274 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

The ACID properties of a transaction keep data safe. In particular, transactions


need to be isolated to ensure data remains consistent in the face of concurrent
access. Isolation necessarily causes contention for shared data. Too much
contention hurts performance and scalability. So what are we to do? Do we
want data to be safe or our system to be fast? The answer is both. Contention
will occur--this is a fact of life. We have to tune our code to ensure that we
minimize it as much as possible. The golden rule is "lock as little data for as
little time as possible". This essentially boils down to one of two things--use the
minimum isolation-level wherever possible, and reduce the execution time of
transactions.

Copyright © 2001, DevelopMentor Inc. 275


Module 7: Transactions

Transaction isolation
Higher isolation results in reduced concurrency

• Speed vs. correctness


• RM can only lock effectively if we tell it our intentions
• Can provide appropriate transaction isolation level
• RM has default isolation level--usually 2
• Choose lowest isolation level your design can stand
• Can change from JDBC API or SQL
• Never change level during a transaction
• Use statement locking hints
• Some of these tricks reduce portability

276 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

Resource Managers implement transaction isolation and ensure that competing


transactions do not interfere with each other. It is fairly easy for the RM to
execute transactions in parallel if they are not accessing the same data. If they
are accessing the same data it is quite straightforward for the RM to figure out
whether individual read or write operations must be isolated or not. It is
impossible though for the RM to figure out the long-term intentions of a
transaction. The author of the transacted operation is the only one who knows
that. If a transaction performs a read, will it perform another one later? If it
does, is it prepared to re-read data that has been modified by another
completed transaction since it last read it? Should the RM hold a read lock until
the transaction ends to stop another transaction from modifying the data
(reduced concurrency, correct data) or just take a read lock whenever the read
occurs and risk another transaction changing the data (improved concurrency,
potentially incorrect data)?
Each transaction has an associated isolation level that determines the
isolation strategy that the RM will use. The author of a transacted operation
sets the transaction isolation level as a categorical hint about which of the four
isolation problems (lost update, dirty read, unrepeatable read, phantom read)
are not likely to occur (or are acceptable if they do occur) based on the logic
of the operation. The transactions isolation levels and the isolation problems
they are guaranteed to solve are shown in figure 7.4. Increasing isolation levels
cumulatively solve each of the problems in turn. For instance, by setting a
transaction isolation level of "repeatable reads" the author is saying "this
operation does perform multiple reads of the same data and I don't want
somebody else changing the data while my operation is looking at it". This tells
the RM that it shouldn't allow another transaction to update the data after this
transaction has read the data and while this transaction is still running.

Degree 0 1 2 2.999... 3

Read Read Repeatable


Common Name Chaos Serializable
Uncommitted Committed Read

Lost Updates? Yes No No No No

Dirty Reads? Yes Yes No No No

Unrepeatable No
Yes Yes Yes No
Reads?

Phantoms? Yes Yes Yes Yes No

Figure 7.4: Transaction isolation levels

Copyright © 2001, DevelopMentor Inc. 277


Module 7: Transactions

There are two major techniques used to implement isolation. One is to use
locks as SQL Server does. Level 1 is implemented using two-phase write locks
(write locks that are held until the end of the transaction). This stops anyone
else from overwriting your changes until after they have been committed at
the end of the transaction. Level 2 is implemented by taking well-formed
(classic) read locks so that you cannot read data that someone else is in the
process of changing. Subsequently you can only read committed data as any
write lock that blocks your read lock is held until the end of the updating
transaction. Level 2.999 is implemented by taking two-phase read locks (read
locks that are held until the end of the transaction). This stops anyone else
getting a write lock after you have started reading as your read lock will not be
released until your transaction ends. Finally, level 3 is implemented by taking
two-phase locks on meta-data to stop anyone inserting or deleting rows into a
table while you are reading from it.
The other technique is versioning, which is used by Oracle 8i. Here, instead
of taking read locks, multiple copies of a piece of data are kept, each one
representing the data's value at a given point in time. When a transaction reads
data, the versions are inspected to figure out what the value of the data was at
any given point in time. When a transaction writes data then a new version of
the data is created (at the end of the transaction if the transaction commits).
A two-phase write lock is taken by any writing transaction to ensure that new
versions of data are appended in order. Old versions of the data are kept as
long as they are needed. Level 1 is automatically satisfied by this scheme
because data is never updated in place--each transaction's changes become a
new version of the data valid at different times--and new versions are not
created until the updating transaction commits. Level 2 is also satisfied
because it is not possible to see dirty data as new versions are only created
when a transaction commits. It turns out that every transaction is marked with
its start time so the transaction has two choices of which data to read--the
version of the data that existed when the transaction started or the latest
visible version. If it reads the latest visible data, then it can see changes made
by transactions that have committed since it started. This means that it suffers
from the unrepeatable read problem. This scheme satisfies level 2 (and 1 by
implication). If it reads the version of the data that was valid at the time it
started then the transaction cannot see changes made by transactions that
have committed since it started. It cannot suffer from unrepeatable reads or
phantom reads so this scheme satisfies levels 2.99 and 3. Versioning really only
allows transactions to run at level 2 or 3.
The versioning scheme would appear to be superior as reads never block.
However, there is one fly in the ointment. Imagine a transaction A running at
level 3 that wants to increment a counter (5 to 6). It is possible for transaction
B to get in after A starts and increment the same counter (from 5 to 6) and
commit the change before A does anything. A then reads the old counter value
as it was when A started (5) and then updates it (to 6) thus overwriting B's
change. In general, a transaction running at isolation level 3 cannot be allowed

278 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

to update data that has changed since it started. Oracle chooses to abort A in
this case. This is particularly problematic to design and code for since it is a
race condition. Not so easy to choose which is best now?
If A is performing a "read-for-update" operation it has to have a way to
guarantee that the data won't change between it being read and updated. It
needs a way to force a write lock at the time the data is read. A different type
of problem occurs with SQL Server and locking. Imagine two concurrent
transactions that both perform a "read-for-update" operation. There is a chance
they could both perform a read and then neither can perform a write since
they both have a read lock, thus blocking the other. Deadlock! SQL Server
chooses to abort one of the transactions. Again, both transactions need a way
to force a write lock at the time the data is read. The SQL SELECT ... FOR
UPDATE syntax achieves this.
The default isolation level for a brand new transaction is level 2 for most
databases. It is possible to set the isolation level associated with a transaction
using the following syntax, set transaction isolation level
repeatable read. The SQL-92 spec says this changes the level for the next
transaction but there are databases where you can change the isolation level of
the current transaction (e.g. SQL Server). Changing the isolation level
associated with a transaction part way through is a dangerous thing to do as it
will affect the behaviour of all subsequent SQL statements and may violate the
semantics of the whole transaction--adjusting it down may cause correctness
problems, adjusting it up may cause performance/deadlock problems. It may
also be possible to change the isolation level associated with a single SQL
statement using a locking hint like this, select * from authors
(repeatable read), valid for SQL Server.
A transaction's isolation level is a key part of its design and the general rule
is to run at the lowest level possible. Transactions that only write can run at
any level above 1. Transactions that only read but do not require accurate data
can run at 0. Transactions that only read, do require accurate data, but don't
require multiple reads of the same data to be consistent can run at 2.
Transactions that only read, do require accurate data, but do require multiple
reads of the same data to be consistent can run at 2.999 (3 for versioning
systems). For transactions that read and write it is hard to give hard-and-fast
advice as it depends on the logic of the operation. Sometimes it may be very
hard to get it right. It depends on the RM you are using (and being able to
predict it ahead of time) and it depends on being able to predict exactly what
other transactions are doing in the system and when. If you are not sure, or
where it might be hard to make such predictions, level 3 should be used to
ensure correctness in all cases (always bearing in mind the versioning/deadlock
problems described above).
The other approach to take is to accept that a higher isolation level causes
more contention but to reduce the time for which that contention occurs. That
is, reduce to a minimum the time the transaction takes to run.

Copyright © 2001, DevelopMentor Inc. 279


Module 7: Transactions

Transactions and time


Keep transaction time down

• Use timeouts
• Commit TX at end of each request method
• Don't let TX span user interaction
• Use sagas for user-driven or long running TXs
• Shorten code path inside transaction
• Acquire resources late/release early
• Aim for a single roundtrip to database
• Work outside of TX where possible
• Defer non-critical work for async processing

280 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

The golden rule is to reduce locks in space and time in order to increase
throughput and maximise scalability. Regardless of the transaction's isolation
level, it is important to ensure that a transaction takes as little time to run as
possible.
It is possible to associate a timeout value with a transaction to set a hard
limit. If the transaction has not ended when the timeout expires then it is
aborted. This is a reasonable approach when transactions can "run away",
transactions can deadlock and transactions can be overwhelmed by the sheer
volume of traffic. The idea is to set the transaction timeout just high enough to
allow "normal" traffic flow. EJB application servers provides you with a way to
do this, as shown in figure 7.5.
Context ctx = new InitialContext();
UserTransaction tx = (UserTransaction)
ctx.lookup("java:comp/UserTransaction");
tx.begin();
tx.setTransactionTimeout(10);
...
Figure 7.5: Setting the transaction timeout

Another way to put a hard limit on the lifetime of a transaction is to ensure


that it starts and ends in the middle-tier (or the database-tier for that matter)
in response to a single client response. Transactions should never span
client/middle-tier interactions because a) there is no guarantee the client will
ever call back into the middle-tier to end the transaction and b) the cost of the
client/middle-tier round trips are incurred as part of the transaction
(unnecessarily extending its length). Certainly never yield a transaction to
human control. EJB enforces this discipline.
If long-running transactions are needed either to span user actions or protect
long-running tasks then the programmer must add logic to compose multiple
short-lived transactions into a long-running "saga" with save points. A simple
example of a saga is the "read-for-update" saga. The client executes a method
in the middle-tier that reads the data from the database in the first transaction
and returns it, ending the transaction. The client updates the data locally and
then calls a second method in the middle-tier to update the data in the
database in a second transaction. Problem is, the second method must ensure
that nobody else has updated the data in the database since it was read and
that the client's update is still valid. To make this possible, a timestamp is
associated with the data in the database. This timestamp is updated whenever
the data in the database is updated. The first method returns the timestamp to
the client with the data. The client presents the updated data, along with the
timestamp it was given, to the second method. The second method compares
the timestamp presented with the timestamp for the latest data in the
database to figure out whether it has changed or not and whether it is
therefore safe for the update to proceed. This is illustrated in figure 7.6. This

Copyright © 2001, DevelopMentor Inc. 281


Module 7: Transactions

is sometimes called "optimistic locking" as the implementation is fairly


optimistic that in most cases the data will not have changed.

Middle-tier
Client
Timestamp+ data
Tx1: SELECT WHERE …
database
Timestamp+ data
Timestamp+ updated data
Tx2: IF … UPDATE …

Figure 7.6: Simple read-for-update saga

The fine-grained way to reduce transaction times is to shorten the execution


time for the transaction, achieved by shortening the code path within the
transaction. Some work can be performed before the transaction starts such as
parameter validation and security checking. Some processing can occur after
the transaction completes such as formatting output. To minimise the
execution time inside the transaction it is especially important to minimise the
number of round-trips to the database. Also, some processing may be non-
critical but must be performed if the transaction commits, such as sending out
a bill of sale for an on-line purchase. This work can be performed
asynchronously later by processing a JMS message sent as part of the
transaction. Figure 7.7 illustrates this.

282 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

check security
validate args
work with cache
acquire resources

start tx
one call to RM
end tx

release resources
perform async processing
format output
Figure 7.7: Shorten code path inside transaction

Copyright © 2001, DevelopMentor Inc. 283


Module 7: Transactions

Distributed transactions
Local transactions can only be used for single-party
transactions. If a system touches multiple resources
managed in different places or involves code
distributed around the network then distributed
transactions are needed.

Copyright © 2001, DevelopMentor Inc. 285


Module 7: Transactions

Distributed transactions
Multi-party transactions

• Dist TX can compose many RMs and distributed agents


• TM is external to all RMs
• Standardized interaction between agent/TM/RMs
• XA used in Java world--JTA is the mapping
• javax.transaction.Transaction and
javax.transaction.XAResource
• XA support normally optional e.g. JMS, JDBC
• javax.sql.XADataSource and javax.sql.XAConnection for JDBC
• Two-Phase Commit needed for safe commit

286 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

Local transactions involve a single agent and a single RM. In some cases an
operation may need to manipulate data from multiple databases, for example.
Alternatively, in a distributed system a transacted operation may be composed
from logic spread over multiple machines. In both of these cases, a distributed
(global) transaction is needed.
A distributed transaction spans multiple interested parties, as shown in
figure 7.8. Apart from having a common understanding of the semantics of a
transaction, all parties also need a common representation of the transaction
and a standard way of propagating it and coordinating it. For this reason,
several competing specifications have emerged to define a model for
distributed transaction processing and an interface between a transaction
manager and the other parties involved in a distributed transaction system: the
RMs and the transactional applications. The one that dominates in the Java
world is the Open Group's XA specification. As can be seen, the distributed
transaction model is much more complex than the local transaction model but
much more powerful.

Distributed transaction

Machine A

agent (root)

RM1 TM1 RM2

agent

RM3 TM2 TM3 RM4

Machine B Machine C
Figure 7.8: Distributed (multi-party) transactions

The programming model for a transactional application is as follows. First,


obtain a transaction from the TM. How this is done is specified by the XA
protocol. Second, obtain required resources from the RMs. Third, ask the TM to
ask the RMs to enlist each the resources on the transaction so they know that
any further access to the resource is part of the transaction. This propagation
of the transaction to the RMs is part of the XA protocol. Fourth, use the
resources. Last, commit (or abort) the transaction. Figure 7.9 illustrates.

Copyright © 2001, DevelopMentor Inc. 287


Module 7: Transactions

RM

agent RM enlist

1. Acquireacquire
resources
tx
2. Acquire transaction enlist
3. Enlist resources on
transaction
4. Use resources TM
5. Commit/abort
transaction

Figure 7.9: Using a distributed transaction - the model

As programmers we are not expected to program the XA wire protocol. The


Java Transaction API is an interface-based specification that represents the
Java mapping of XA. Transaction processing systems implement it and
transactional applications use it. There are three main interfaces to
concentrate on: javax.transaction.TransactionManager represents the
transaction manager, javax.transaction.Transaction represents the
transaction and javax.transaction.XAResource represents a resource
that can be enlisted into an XA transaction.
The JDBC 2 extension specification describes the interfaces that have to be
implemented by a provider so that a connection may be enlisted into a
distributed transaction: javax.sql.XADataSource and
javax.sql.XAConnection. The provision of these interfaces is not
mandatory, so you must choose the driver carefully. If the provider does have
support for distributed transactions then the code for obtaining the connection
changes slightly and is shown in figure 7.10.
XAConnection con getXAConnection() {
Context ctx = new InitialContext();
XADataSource ds =
(XADataSource)ctx.lookup("jdbc/MyXADS");
return ds.getXAConnection();
}
Figure 7.10: Obtaining a "distributed TX-aware" JDBC connection

288 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

The code to enlist this connection into a distributed transaction is shown in


figure 7.11. The application server may or may not provide the programmer
with direct access to the Transaction Manager. If it does then it will have a
proprietary bootstrap mechanism. The code shows two possibilities: one where
the code performs a JNDI lookup on a previously bound TM class and one where
the code instantiates the TM class directly. Once the TM is obtained it can be
used to start the transaction with TransactionManager.begin()
(TransactionManager.getTransaction() is used to obtain a reference to
the transaction). The javax.sql.XAConnection can be used to obtain an
javax.transaction.XAResource via XAConnection.getXAResource().
This is then used to enlist the connection into the transaction using
Transaction.enlistResource(). Finally, after using the connections,
Transaction.commit() is used to commit the transaction. Notice how
Transaction.rollback() is called if any exception occurs.
try {
TransactionManager tm = ctx.lookup("TM");
// or TransactionManager tm = new SomeTMClass();
tm.begin(); Transaction tx = tm.getTransaction();
XAConnection con1 = getXAConnection();
XAConnection con2 = getXAConnection();
XAResource xar1=con1.getXAResource();
XAResource xar2=con2.getXAResource();
tx.enlistResource(xar1); tx.enlistResource(xar2);
Statement stmt = con1.getConnection().createStatement();
Statement stmt2 = con2.getConnection().createStatement();
stmt1.executeUpdate(
"update savings set amount = amount + 10 Where id =
1000");
stmt2.executeUpdate(
"update checking set amount = amount - 10 Where id =
1000");
tx.commit();
}
catch(...) { tx.rollback(); }
Figure 7.11: Using JDBC with a distributed transaction

But what actually happens when we ask the TM to commit the transaction? It is
not possible for it to go to each RM participating in the transaction in turn and
tell it to commit changes. Figure 7.12 illustrates what happens if we do this.
The last RM decides to fail the commit after all others have already committed.
Not particularly atomic! To solve the problem, the TM initiates a "two-phase
commit" protocol (2PC) shown in figure 7.13. The first phase is the "prepare
phase". The TM asks each RM in the transaction to vote whether it wants to
commit or abort. Any RM that has voted to commit MUST be prepared to
commit the changes. If all RMs vote to commit then the transaction will

Copyright © 2001, DevelopMentor Inc. 289


Module 7: Transactions

commit. If any RM votes to abort then the transaction will abort. At the end of
phase one the TM knows the outcome of the transaction. The second phase is
the "notification phase". Each RM is notified of the transaction outcome and
must commit or abort changes as necessary. If the TM loses contact with any
RM before the end of phase one and can't get its vote, then phase two cannot
proceed as the transaction outcome is still in doubt as far as the TM is
concerned, and the transaction is subject to timeout expiry, if it has one. If the
TM loses contact with any RM after the end of phase one but before the end of
phase two, then the transaction outcome is still in doubt as far as the
disconnected RM is concerned. The 2PC protocol defines a recovery sequence if
either of these situations should occur. Not only is it important for the RM to
record any data changes made under a transaction, but also for it and the TM
to log any communication they were having concerning the transaction so that
recovery can be attempted if TM and RM lose contact.

RM 4 o! OK RM 1
N
TM

OK OK
RM 3 RM 2

Figure 7.12: The problem of coordinating multi-party commit

Phase 1: vote
agent TM
Phase 2: notify RM
Commit
Phase 1: vote
Result
Phase 2: notify RM

Figure 7.13: Ending a distributed transaction - 2 Phase Commit

Obviously distributed transactions are much slower to execute than local


transactions because of their distributed nature. For this reason it is always
wise to prefer local transactions over distributed transactions wherever
possible.

290 Copyright © 2001, DevelopMentor Inc.


Module 7: Transactions

Summary
• Transactions essential for protecting state
• Systems does hard work, simple commit/abort model for client
• Transactions=contention so reduce locking in space and time
• Work hard to minimize transaction time in your code
• Provide hard limit for TX : timeouts and method end
• Use sagas for user tasks/long running tasks
• Protect single resources with local transactions
• Protect multiple resources with distributed transactions

Copyright © 2001, DevelopMentor Inc. 291


Module 8

EJB Declarative
Transactions

Copyright © 2001, DevelopMentor Inc. 293


Transactions by stealth

After completing this module, you should be able to:


 understand how the container manages transactions
 appreciate the options for composing transacted objects
 learn how objects influence transaction outcome
 understand appropriate behaviour for transacted objects

294 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

Managed Transactions
Transactions may be required for consistency but
not all bean developers want to write code to
explicitly manage them. Containers use interception
to hide the details (but not the presence) of
transactions, leaving the bean developer to focus
more on the problem in hand.

Copyright © 2001, DevelopMentor Inc. 295


Module 8: EJB Declarative Transactions

Managed transactions
Container interception model hides TX management detail

• It starts transaction when needed/asked


• It puts transaction in bean's context
• It widens "scope" of transaction to include cooperating beans
• It enlists resources into transaction when first used
• It ends transaction when needed/asked
• It allows participating beans to help decide TX outcome

296 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

The container insulates an EJB within a managed environment. More


specifically, the container intercepts all calls into a bean, all calls out of a
bean (to another bean), and all access to managed resources (such as JDBC
connections). This allows the container to detect any situation where a
transaction may need to be started, propagated from one bean to another
(widening the "scope" of the transaction) or ended, where a decision may need
to be made about transaction outcome, or where a resource may need to be
enlisted on the current transaction. This arrangement is shown in the following
figure 8.1
Container code

Start
transaction
Container code
remote Propagate remote
Bean A interface
interface transaction Bean B
Commit/abort
transaction

Container
code
Enlist on
transaction

JDBC Driver

Figure 8.1: Container uses interception to manage transactions

The transaction is always started by container code, either because it detects


that there currently isn't a transaction "in scope" and the called bean requires
one or because the bean asked for one to be started programmatically. Once
started on behalf of a bean, the transaction is stored in a "well-known place" in
the bean's context. This is where the container interception code looks when it
needs to silently propagate a transaction from one bean to another thus
widening its scope, or it needs to silently enlist a resource on the transaction
upon first usage. Note that any managed resource used by the bean is provided
by the container as the result of a JNDI lookup. This gives the container the
chance to layer services (e.g. JDBC connection pooling and transaction auto-
enlistment) on top of the raw resource (e.g. the real JDBC driver code) where
necessary. The bean notices no difference as the service layer impersonates
the underlying layer. To configure the additional service layer, for example, a
pooled transactional JDBC driver, there is normally some vendor-specific
administration mechanism. The container documentation will provide details.
The transaction is always ended by container code and all beans participating
in the transaction get a chance to vote in its outcome (more on this later).
From this perspective the container always "manages" the transaction and the
bean code must not do anything to interfere with this. For instance, bean code
that is part of a managed transaction must not call the JDBC Connection's
commit() or setAutoCommit() methods.

Copyright © 2001, DevelopMentor Inc. 297


Module 8: EJB Declarative Transactions

As a result of hiding the details of transaction code, the container may


support local or global transactions. It will be important for you to know which
of these is supported. Remember that local transactions are faster but are
scoped to one type of resource, e.g. a single JDBC connection, a single JMS
session etc. Global (distributed) transactions are slower but enable you to
coordinate the use of many different resource types across many different
machines as part of the same transaction. Again, see the container
documentation for details.

298 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

Managed transaction types


Extent of management by container depends on bean's transaction type

• Specified by <transaction-type> deployment attribute


• Container-managed: bean's TX managed totally by container
• Bean specifies intent declaratively to effect how TXs bracketed/scoped
• Bean-managed: bean has more programmatic control
• Can choose TX demarcation and timeout, container deals with all other
aspects

300 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

Even though the container always manages the important aspects of a


transaction, there are two levels of management. A bean can be marked in its
deployment descriptor as using a "container-managed" transaction (CMT). From
the bean's perspective, this means that it requires the container to deal with
all aspects of any managed transaction it takes part in and the bean code
needn't contain any transaction-related code. The bean deployer must also
assign other attributes to the bean in its descriptor that decide exactly how,
where and whether the bean is to be composed into a managed transaction.
For a little more control, the bean can be marked in its deployment
descriptor as using a "bean-managed" transaction (BMT). This is still a
transaction managed by the container but in this case the bean code decides
when (and whether) transactions are to be started and ended by the container
on its behalf. The bean code contains minimal transaction-related code and no
other declarative transactional attributes are required.

Copyright © 2001, DevelopMentor Inc. 301


Module 8: EJB Declarative Transactions

Container-managed transactions
Bean's perspective: TX completely managed by container

• <transaction-type>Container</transaction-type>
• Transaction bracketing/scoping decided by <transaction-attribute>
• "Root" bean interceptor causes creation of transaction scope
• "Root" bean interceptor ends transaction

302 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

The following table 8.2 shows how the declarative transactional attributes for a
CMT bean affect the bracketing and scoping of a managed transaction.

<transaction-attribute> Meaning
NotSupported Cannot and does not take part in tx

Never As NotSupported but fails if caller in tx


Supports Ambivalent, may be in a TX or not

Required Must have a tx, will use caller’s if available


RequiresNew Must have a tx, will not use caller’s if available

Mandatory Must use caller’s tx, will fail if not available

Figure 8.2: Declarative transaction attributes for a CMT bean

The deployment descriptor in figure 8.3 shows how to annotate a CMT bean.
Notice the common practice of providing a default transactional attribute for
all methods in the bean's remote interface and then overriding the
transactional attribute for specific methods.

Copyright © 2001, DevelopMentor Inc. 303


Module 8: EJB Declarative Transactions

<ejb-jar>
<enterprise-beans><session>
<ejb-name>Teller</ejb-name>
<transaction-type>Container</transaction-type>
</session></enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Teller</ejb-name>
<method-intf>Remote</method-intf>
<method-name>*</method-name>
</method>
<trans-attribute>NotSupported</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>Teller</ejb-name>
<method-intf>Remote</method-intf>
<method-name>transfer</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
Figure 8.3: Deployment descriptor for a bean using a container-managed
transaction

When one bean calls to another, the container interception layer has to make a
decision. If the calling bean is part of an existing managed transaction then
should the transaction flow to the called bean so that it becomes part of the
same transaction thus widening the transaction scope? If not, or if the calling
bean is not part of an existing managed transaction, then should a new
managed transaction be started for the called bean? If the called bean is a CMT
bean then its transactional attribute is used by the container to make that
decision. The result is portrayed more graphically in figures 8.4 and 8.5. In the
first diagram, a bean that is already part of an existing managed transaction
calls out to a variety of CMT beans with different transactional attributes. In
the second, a bean that is not already part of a managed transaction does the
same. As each CMT bean gets called, each with a potentially different
transactional attribute, notice how the transaction boundary is decided
according to the transaction attributes. It should be apparent that a CMT bean
with attributes of Mandatory, Supported or Required can be composed
into an existing managed transaction. Also, two different transaction scopes
means two independent transactions--the outcome of the second transaction is
completely decoupled from the first. A second transaction scope is needed to
perform transacted work outside of the current transaction. This could be

304 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

useful for scenarios such as transacted auditing where you want to audit a
transacted operation, regardless of its outcome. A bean that causes a new
transaction scope to be created guarantees itself to be the root of the
transaction and ensures that its commit logic is not subsumed by a bean further
up the hierarchy.
tx scope 2
calls NotSupported CMT bean RequiresNew CMT bean
tx scope 1
bean in
managed tx Supports CMT bean
Required CMT bean
error! Mandatory CMT bean

Never CMT bean

Figure 8.4: Effect of CMT bean declarative attributes on transaction


bracketing/scope (1)

calls tx scope 2

Never CMT bean NotSupported CMT bean RequiresNew CMT bean

bean outside
of managed Supports CMT bean
tx
tx scope 1
error!
Required CMT bean
Mandatory CMT bean

Figure 8.5: Effect of CMT bean declarative attributes on transaction


bracketing/scope (2)

If a CMT bean is the one whose declarative transaction attribute caused a new
transaction scope to be created, then it is deemed the "root" of the transaction
scope. This root bean is special for a number of reasons. Notionally the root
CMT bean's interceptor causes the transaction to start, although practically this
is not necessarily the case as the container may delay starting the transaction
until it is actually required. The transaction will be ended when the flow of
control gets back to the root CMT bean's interceptor. Assume CMT beans A, B,
C, D are in the same transaction scope with A (TX=Requires New or Required)
as the root and B (TX=Required), C (TX=Supported) and D (TX=Mandatory) as
sub-objects. Let us say that A calls B which calls C and then A calls D. See
figure 8.6 for details. When A is called, the call passes to A through its
interposer that starts the transaction. When the call chain completes i.e. ->A-
>B->C->B->A->D->A-> the call will pass back out through A's interceptor which
will end the transaction. CMT transactions NEVER span root methods.

Copyright © 2001, DevelopMentor Inc. 305


Module 8: EJB Declarative Transactions

tx scope

C (Supported)
tx root

Starts tx on way in A (Required or


B (Required)
Stops tx on way out Requires New)

D (Mandatory)

Figure 8.6: The lifetime of a container-managed transaction

Figure 8.7 is a table further summarizing the relationship between the root
bean and the transaction scope.
in tx shares callers root of tx
<transaction-attribute>
scope? tx scope? scope?
NotSupported Never Never Never

Never Never Never Never

Supports if caller is if caller has one Never


if caller doesn’t
Required Always if caller has one
have one
RequiresNew Always Never Always

Mandatory Always Always Never

Figure 8.7: Effect of CMT bean declarative attributes on transaction


bracketing/scope (3)

Notice in the following figure 8.8 how the code for this CMT bean is just regular
JDBC data access code that takes advantage of, but doesn't interfere with, the
managed transaction.

306 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

public void transfer()<-- 1. Container starts tx


{
try {
DataSource ds=jndictx.lookup("jdbc/MyDB");
Connection con=null;
con=ds.getConnection();<-- 2. Container enlists
connection in tx
Statement stmt=con.createStatement();
String sql=null;
sql = "UPDATE xx set yy = val - " + " 500 where id=1";
stmt.executeUpdate(sql);
sql = "UPDATE vv set ww = val + " + " 500 where id=1";
stmt.executeUpdate(sql);
// Call downstream EJB created earlier
logBean.logtransfer();<-- 3. Container propagates tx
to another CMT bean
}
catch (Exception e) {
// Oops - deal with failure
}
}<-- 4. Container ends tx
Figure 8.8: Method code for a root CMT bean

Copyright © 2001, DevelopMentor Inc. 307


Module 8: EJB Declarative Transactions

CMT beans and transaction outcome


Container attempts to commit managed TX if passive consent

• Root CMT bean interceptor aborts if at least one unhappy bean in scope
• Bean can show displeasure via EJBContext.setRollbackOnly()
• Bean can show displeasure via "System" exception (remote or runtime
exception)
• "System" exception discards bean instance
• TX doomed but won't end immediately
• EJBContext.getRollbackOnly() aids fast fail

308 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

At the end of a managed transaction, the container must make a decision about
whether to attempt to commit the transaction or whether to abort it. How is
this decision made? Basically, if the code that causes the managed transaction
to start/end is happy and all CMT beans composed into the managed
transaction are happy, then the container attempts to commit the transaction.
In the case of a container-managed transaction, this means that the container
(in the shape of the root interposer) will only attempt to commit the
transaction if all CMT beans composed into the managed transaction are happy.
Otherwise it will abort.
Remember that all code fragments that execute cooperatively as part of the
same transacted operation must atomically succeed or fail together as a whole.
Some of the code in a transaction is part of the system, e.g. the Transaction
Manager, plus all enlisted Resource Managers. Even if the container attempts to
commit the managed transaction there is no guarantee that it will commit as
part of the system code may object, in which case the transaction would abort.
This might happen, for instance, if the Transaction Manager decided that the
transaction had timed out before the container could start the committal
process.
So how does a container know whether a CMT bean composed into a
managed transaction is happy or not? It is based on passive consent. If a bean
does nothing to indicate it is upset then the container will assume that it has
completed its work successfully. However, a bean can show its displeasure by
latching a "rollback-only" bit that marks the managed transaction it is taking
part in as doomed so that it can never commit. If any bean in the transaction
sets this bit it cannot be reset and the transaction will be aborted. There are
two ways for a bean to indicate its displeasure and set the "rollback-only" bit.
First, it can call its EJBContext.setRollbackOnly() method. Second, it
can throw a system exception. This means a runtime exception, i.e.
java.lang.RuntimeException or one of its subtypes, or a remote
exception, i.e. java.rmi.RemoteException or one of its subtypes. If such a
system exception is not handled and gets back to the container (e.g. the
interceptor of any bean in the transaction scope) then the "rollback-only" bit is
set. Note that application exceptions (checked exceptions) do not cause the
current managed transaction to rollback automatically when the container
detects them.
Either of the following two code snippets will cause the transaction to be
doomed. Figure 8.9 shows the bean calling
EJBContext.setRollbackOnly(). Figure 8.10 shows the bean throwing an
EJBException runtime exception.

Copyright © 2001, DevelopMentor Inc. 309


Module 8: EJB Declarative Transactions

public void transfer()


{
try {
DataSource ds=jndictx.lookup("jdbc/MyDB");
Connection con=null;
con=ds.getConnection();
Statement stmt=con.createStatement();
String sql=null;
sql = "UPDATE xx set yy = val - " + " 500 where id=1";
stmt.executeUpdate(sql);
sql = "UPDATE vv set ww = val + " + " 500 where id=1";
stmt.executeUpdate(sql);
logBean.logtransfer();
}
catch (Exception e) {
ctx.setRollbackOnly();<-- 1. Transaction now doomed
throw e;
}
}<-- 2. Container aborts tx if bean is root
Figure 8.9: CMT bean dooms transaction - technique 1

public void transfer()


{
try {
DataSource ds=jndictx.lookup("jdbc/MyDB");
Connection con=null;
con=ds.getConnection();
Statement stmt=con.createStatement();
String sql=null;
sql = "UPDATE xx set yy = val - " + " 500 where id=1";
stmt.executeUpdate(sql);
sql = "UPDATE vv set ww = val + " + " 500 where id=1";
stmt.executeUpdate(sql);
logBean.logtransfer();
}
catch (Exception e) {
String s = e.getMessage();
throw new EJBException(s);<-- 1. Transaction doomed if
exception gets back
to container
}
}<-- 2. Container aborts tx if bean is root
Figure 8.10: CMT bean dooms transaction - technique 2

What is the difference between calling EJBContext.setRollbackOnly()


and throwing a system exception? When the container detects a system

310 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

exception it assumes something has gone badly wrong. As well as marking the
transaction for rollback, the interposer discards the bean instance. This is no
big deal for stateless session beans and entity beans as they can be recreated
behind the scenes but it is significant for stateful session beans as they acquire
conversational state over time. If an attempt is made to access a discarded
stateful session bean instance then a java.rmi.NoSuchObjectException
exception will be encountered. The container always (re)throws system
exceptions as java.rmi.RemoteException or one of its subtypes. System
exceptions thrown by a non-root CMT bean composed in a managed transaction
will always be re-thrown as a
java.transaction.TransactionRolledbackException remote
exception. This indicates to the caller in no uncertain terms that the
transaction is doomed and no more work should be done. System exceptions
explicitly thrown out of the transaction scope by the root bean to its caller will
always be thrown as a java.rmi.RemoteException or a subtype with the
system exception as a nested type. Figures 8.11, 8.12 and 8.13 illustrate. If the
bean code wants to explicitly throw a runtime exception (as opposed to
generating one accidentally) then javax.ejb.EJBException, or something
derived from it, is preferred.
CMT bean (ta=Required, Supports or Mandatory)
Bean throws… Interposer catches and takes following action…
No exception to catch, no exception thrown to caller
No exception Bean tx marked for rollback if EJBContext.setRollbackOnly called
Bean not discarded
Exception re-thrown to caller
Application exception Bean tx marked for rollback if EJBContext.setRollbackOnly called
Bean not discarded
javax.transaction.TransactionRolledbackException thrown to caller
System exception Bean tx marked for rollback
Bean discarded

When tx already doomed, calling non-root CMT bean causes its interposer to
throw a javax.transaction.TransactionRolledbackException to caller and discard
the bean

Figure 8.11: Effect of uncaught exceptions : non-root CMT bean in any


managed transaction

Copyright © 2001, DevelopMentor Inc. 311


Module 8: EJB Declarative Transactions

CMT bean (ta=Never, NotSupported or Supports)


Bean throws… Interposer catches and takes following action…
No exception to catch, no exception thrown to caller
No exception Callers tx (if any) unaffected *
Bean not discarded
Exception re-thrown to caller
Application exception Callers tx (if any) unaffected *
Bean not discarded
javax.rmi.RemoteException thrown to caller
System exception Callers tx (if any) unaffected *
Bean discarded

* Two different managed transaction scopes always yield independent transactions


that are completely decoupled from each other

Figure 8.12: Effect of uncaught exceptions : CMT bean outside of a managed


transaction

CMT bean (ta=RequiresNew or Required)


Bean throws… Interposer catches and takes following action…
No exception to catch, no exception thrown to caller
Abort bean tx if marked for rollback, attempt commit otherwise
No exception
Bean not discarded
Callers tx (if any) unaffected *
Exception re-thrown to caller
Abort bean tx if marked for rollback, attempt commit otherwise
Application exception
Bean not discarded
Callers tx (if any) unaffected *
java.rmi. RemoteException thrown to caller **
Bean tx aborted
System exception
Bean discarded
Callers tx (if any) unaffected *

** Or a sub-type of

Figure 8.13: Effect of uncaught exceptions : root CMT bean in a container-


managed transaction

Note the following from the above figures. First, if a subtype of


java.rmi.RemoteException is thrown by the CMT root bean and not
handled then this exception is thrown out of the transaction scope unchanged.
This includes the likely case where a CMT non-root bean interposer throws a
java.transaction.TransactionRolledbackException and the CMT
root bean doesn't handle it. Second, as mentioned before, two different
transaction scopes means two independent transactions--the outcome of the
calling transaction is completely decoupled from the outcome of the called
transaction and vice versa.

312 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

When the "rollback-only" bit is set for the managed transaction it will not
abort the transaction straight away. Rather a decision will be made when the
transaction ends. It makes sense to avoid wasting time executing further work
as part of a transaction that is ultimately doomed. We have already seen that if
any bean in a managed transaction detects a system exception then it can infer
that the transaction is doomed. If a bean in a managed transaction detects an
application exception then what can it deduce? The bean that threw the
exception may have set the "rollback-only" bit or it may not. In this case there
is a method that can be called to check the state of the "rollback-only" bit--
EJBContext.getRollbackOnly(). If a bean executing as part of a managed
transaction suspects that something has gone wrong then it should call this
method to check. If the "rollback-only" bit is not set then the bean could
attempt recovery and carry on. If the "rollback-only" bit is set then the bean
should fail fast and hasten the end of the transaction.
So it seems there are three strategies for a CMT bean. If you want to
indicate to your caller that something is wrong without marking the transaction
for rollback then throw an "expected" application exception. This allows your
caller to handle the exception and attempt recovery. Care must be taken when
allowing an application exception to be passed back out of the transaction
scope by a CMT root bean as the container attempts to commit the transaction.
In this case it may be counter-intuitive for the caller of the CMT root bean to
receive an exception but have the transaction commit. If you want to indicate
to your caller that something is wrong and you want to force the transaction to
abort, AND you don't want the container munging your exception, then throw
an application exception and call EJBContext.getRollbackOnly(). If you
want to indicate to you caller that something is wrong (or some unpredictable
runtime error has occurred) and you want to force the transaction to abort AND
you don't mind the container munging your exception then throw a system
exception (or fail to handle a runtime exception).

Copyright © 2001, DevelopMentor Inc. 313


Module 8: EJB Declarative Transactions

Bean-managed transactions
Provide more flexibility as container-managed TXs have issues

• <transaction-type>Bean</transaction-type>
• Bean code calls EJBContext.getUserTransaction()
• Bean code programs against UserTransaction interface
• Bean decides whether or not to have a transaction
• Bean brackets transaction
• Bean must follow some rules

314 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

Container-managed transactions are quite prescriptive. It is only possible to


have a single transaction or no transaction. You may wish to choose at run-
time. It is not possible to decide exactly when a transaction starts and ends
and it is not possible to (according to the EJB 1.1 spec) decide transaction
timeout. Both of these are important factors when trying to keep transaction
times down. It is not possible to decide whether to use local or distributed
transactions. The container will decide for us. Local transactions are very much
lower overhead than distributed transactions and should be preferred where
possible. We would like to be able to choose whether or not to have a
transaction, when that transaction might start and what timeout to give it.
Enter bean-managed transactions.
A BMT bean manages its transaction by acquiring and manipulating a
javax.transaction.UserTransaction interface. The bean obtains this
interface using the EJBContext.getUserTransaction() method. The
interface is implemented by the container and provides the bean with the
ability to bracket its own transaction. In the following code fragment 8.14 the
bean is able to start and end the transaction when desired. Note how the code
sets the transaction timeout. Transactions should execute as quickly as
possible--system throughput is typically the inverse of transaction time. To
ensure that runaway/deadlocked code doesn't hang the system, incomplete
transactions are forced to abort at timeout expiry, thus releasing any locks
they hold and allowing other transactions to unblock and complete. If no
transaction timeout is set like this, then each managed transaction (CMT or
BMT) will have a default timeout set by the container. Calling
setTransactionTimeout(0) means no expiry.

Copyright © 2001, DevelopMentor Inc. 315


Module 8: EJB Declarative Transactions

public void transfer()


{
UserTransaction ut = null;
try {
ut = ctx.getUserTransaction();
ut.begin();<-- 1. Container starts tx with beans help
ut.setTransactionTimeout(5);
DataSource ds=jndictx.lookup("jdbc/MyDB");
Connection con=null;
con=ds.getConnection();<-- 2. Container enlists
connection in tx
Statement stmt=con.createStatement();
String sql=null;
sql = "UPDATE xx set yy = val - " + " 500 where id=1";
stmt.executeUpdate(sql);
sql = "UPDATE vv set ww = val + " + " 500 where id=1";
stmt.executeUpdate(sql);
// Call downstream EJB created earlier
logBean.logtransfer();<-- 3. Container propagates tx
to CMT bean
ut.commit(); <-- 4. Container ends tx with beans help
}
catch (Exception e) {
ut.rollback();
}
}
Figure 8.14: Method code for a BMT bean

The deployment descriptor in figure 8.15 shows how to annotate a BMT bean.
Notice how there is no longer any need for declarative transaction attributes
because now the bean decides whether it needs a transaction or not and
exactly when the transaction stops and starts. Notice also how methods are not
individually annotated as they are for CMT beans. Each method decides
programmatically whether it wants a transaction or not.
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Teller</ejb-name>
<transaction-type>Bean</transaction-type>
...
</session>
</enterprise-beans>
...
</ejb-jar>
Figure 8.15: Deployment descriptor for a bean using a bean-managed
transaction

316 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

Because the bean code uses the UserTransaction interface to explicitly


bracket the transaction, it has become the "root" (client) of the bean-managed
transaction (assuming it has one) and plays more or less the same role as the
CMT root bean interposer does in a container-managed transaction. A BMT bean
is either the root of a new managed transaction or it does not execute as part
of a transaction. Either way it can never be composed into an existing managed
transaction. Other CMT beans can, however, be composed into a bean-managed
transaction. Assume a BMT bean A and CMT beans B, C, D are in the same
transaction scope with A as the root (it starts and ends the managed
transaction) and B (TX=Required), C (TX=Supported) and D (TX=Mandatory) as
sub-objects. A starts the transaction with UserTransaction.begin() and
then calls B which calls C and then A calls D. Finally, A ends the transaction
with UserTransaction.commit() (or UserTransaction.rollback()).
BMT bean A defines the lifetime of the transaction as shown in figure 8.16.
tx scope

C (Supported)
tx root
A (Bean-managed)
B (Required)
UserTransaction.begin();

UserTransaction.commit(); D (Mandatory)

Figure 8.16: The lifetime of a bean-managed transaction

The following table 8.17 shows how a BMT bean affects the scoping of a
managed transaction.
<transaction-type> Meaning
Like RequiresNew if bean starts tx
Like NotSupported if bean doesn’t start tx
shares callers
Bean in tx scope? root of tx scope?
tx scope?
Yes if bean starts tx Yes if bean starts tx
Never
No if bean doesn’t start tx No if bean doesn’t start tx

Figure 8.17: Effect of BMT bean on transaction bracketing/scope (1)

Figure 8.18 shows how a BMT bean affects the bracketing/scope of a managed
transaction.

Copyright © 2001, DevelopMentor Inc. 317


Module 8: EJB Declarative Transactions

bean outside BMT bean that doesn’t start a tx tx scope 1


of managed
tx BMT bean that starts a tx

bean in BMT bean that doesn’t start a tx tx scope 2


managed tx
BMT bean that starts a tx

tx scope 1

Figure 8.18: Effect of BMT bean on transaction bracketing/scope (2)

It turns out that entity beans must be marked for CMT (TX=Required) assuming
they need a transaction at all. The reason for this is so that entities behave
correctly when composed inside an existing managed transaction and remain
self-consistent when used outside of a managed transaction. The exact details
are discussed in a later section.
The bean-managed transactions that are programmable from bean code can
also be programmed from other code within the application server, such as
Servlets or JSPs. Figure 8.19 illustrates such a "client-managed" transaction.
public class MyServlet extends HttpServlet {
public void doPost() ... {
javax.transaction.UserTransaction tx = null;
try {
Context ctx = new InitialContext();
Object o = ctx.lookup("TellerSessionHome");
TellerSessionHome th=(TellerSessionHome)o;
TellerSession t=th.create();
tx =
(UserTransaction)ctx.lookup("java:comp/UserTransaction");
Money m = 250;
tx.begin();
t.deposit();
t.getbalance();
tx.commit();
}
catch (Exception e) {
tx.rollback();
}
}
}
Figure 8.19: A client-managed transaction in a Servlet

318 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

BMT beans and transaction outcome


Container attempts to commit TX if passive consent

• UserTransaction.rollback() will always abort


• UserTransaction.commit() aborts if at least one unhappy bean in
scope
• javax.transaction.RollbackException exception thrown in this
case
• CMT beans affect bean-managed TX in usual way
• UserTransaction.getStatus() aids fail fast

320 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

We discussed before how the container will attempt to commit a managed


transaction if the code that causes the managed transaction to start/end is
happy and all CMT beans composed into the managed transaction are happy. In
the case of a bean- or client-managed transaction, if the bean or client code
calls UserTransaction.rollback() then the transaction will abort. If the
bean or client code calls UserTransaction.commit(), then the container
will only attempt to commit the transaction if the BMT bean that bracketed the
transaction and all CMT beans composed into the bean-managed transaction
are happy according to the rules established earlier and encoded in 8.11.
Otherwise it will abort.
A typical usage pattern for a bean-managed transaction was shown in figure
8.14. That is, the bean starts the transaction and then performs its
transactional work within a try block so that if an exception occurs then it can
be handled and the appropriate action can be taken to end the transaction.
Assuming that pattern, figure 8.20 encodes the outcome when the BMT bean
handles an exception thrown by itself (or a downstream CMT bean) and calls
either UserTransaction.commit() or UserTransaction.rollback().
Notice that UserTransaction.rollback() aborts the transaction no matter
what any other CMT bean in the transaction scope might think. The outcome of
the transaction and how the BMT bean returns to its caller are independent. If
the BMT bean decides to throw an unhandled exception back to its interposer
after the bean-managed transaction has ended, then the result would be the
same as if a CMT bean (TX=Never, NotSupported or Supports) composed outside
of a managed transaction threw an unhandled exception back to its interposer,
as encoded in figure 8.12 shown earlier.
BMT bean (no transaction attributes)
Bean throws
Bean catches and ends tx with UserTransaction.commit()/rollback()…
inside of tx…
UT.commit() attempts to commit bean tx if not marked for rollback
No exception UT.rollback() aborts bean tx ***
Callers tx (if any) unaffected *
UT.commit() attempts to commit bean tx if not marked for rollback
Application
UT.rollback() aborts bean tx ***
exception
Callers tx (if any) unaffected *
UT.commit() aborts bean tx
System
UT.rollback() aborts bean tx ***
exception
Callers tx (if any) unaffected *

*** UserTransaction.rollback() ALWAYS aborts the bean-managed transaction

If bean throws uncaught exception back to interposer behaviour is the same as


for CMT (ta=Never, NotSupported or Supported bean) outside of a managed tx

Figure 8.20: Effect of caught exceptions : root BMT bean in bean-managed


TX

Copyright © 2001, DevelopMentor Inc. 321


Module 8: EJB Declarative Transactions

What if the code pattern shown in 8.14 was not adopted? What if the bean
didn't bother to handle exceptions and/or didn't bother to call
UserTransaction.commit() or UserTransaction.abort() to explicitly
end the transaction? A bean-managed transaction in a stateless session cannot
span root methods so it behaves the same as a container-managed transaction
in that sense. That is, if one BMT bean method starts the transaction then the
same one must end it within the same invocation. The container aborts the
transaction if the BMT method ends without calling
UserTransaction.commit() or UserTransaction.abort() and the
interposer re-throws a java.rmi.RemoteException back to the caller of the
BMT bean method. This behaviour makes sense as stateless session beans are
reused by different clients across invocations. On the other hand, a bean-
managed transaction in a stateful session can span root methods. Although this
is legal because the stateful session bean is dedicated to one client, it is
potentially a dangerous thing to do if the call to the bean method that ends the
transaction can not be assured. Figure 8.21 tells the story.
BMTstateful session bean (no transaction attributes)
Bean throws Interposer catches without bean calling
inside of tx… UserTransaction.commit()/rollback()…
No exception to catch, no exception thrown to caller
Bean tx keeps running ****
No exception
Bean not discarded
Callers tx (if any) unaffected *
Application exception re-thrown to caller
Bean tx keeps running ****
No exception
Bean not discarded
Callers tx (if any) unaffected *
java.rmi. RemoteException thrown to caller **
Bean tx aborted
System exception
Bean discarded
Callers tx (if any) unaffected *
**** If the transaction has been marked for rollback it will eventually abort

Bean-managed tx for stateless session BMT beans NEVER spans


root methods - container aborts tx and throws java.rmi.RemoteException

Figure 8.21: Effect of uncaught exceptions : root BMT stateless session bean
in bean-managed TX

BMT bean code mustn’t call EJBContext.setRollbackOnly() or


EJBContext.getRollbackOnly(). Instead, UserTransaction equivalents
should be used. A BMT bean or client can doom the transaction by calling
UserTransaction.setRollbackonly() and discover the current status of
the transaction using UserTransaction.getStatus().

322 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

CMT stateful session beans and TX outcome


Stateful sessions beans may need to know TX outcome

• Stateless session beans don't care


• Stateful session beans hold conversational state in memory
• Memory not covered by transactional semantics
• BMT stateful sessions know TX outcome
• CMT stateful sessions can find out

324 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

A stateless session bean instance that is part of a managed transaction does not
need to be notified of the transaction outcome when it ends. The bean
instance deactivates at the end of the transaction and cannot keep any volatile
shared state in memory across invocations because either it will be destroyed
or it will be pooled for reuse by another client. A stateless session typically
reads shared state from persistent store, manipulates it and then writes it back
to persistent store, all within a single method invocation. Such state is
normally manipulated under transactional control and the persistent store is
the "source of truth".
Stateful sessions may need to know the transaction outcome since they do
keep conversational state and transactional semantics don't cover state held in
memory. The bean must know the transaction outcome in order to keep its
state consistent. As we have seen, BMT stateful sessions know the transaction
result because they call UserTransaction.commit() or
UserTransaction.rollback(). CMT stateful session beans can also
discover transaction-related events by implementing the
javax.ejb.SessionSynchronization interface and marking themselves
Required, RequiresNew or Mandatory to ensure they partake in a managed
transaction. The interface is shown in 8.22. Note that the
beforeCompletion() method is the last chance for the bean to mark the
transaction for rollback.
// CMT stateful session bean implements this for
// Notification of transaction-reletaed events

public interface javax.ejb.SessionSynchronization {


// Called before invoking first method in tx
public void afterBegin() throws RemoteException;
// Called just before transaction enters commit phase.
// Last chance to abort with setRollbackOnly()
public void beforeCompletion() throws RemoteException;
// Called after transaction end with tx outcome
public void afterCompletion(boolean committed)
throws RemoteException;
}
Figure 8.22: How CMT stateful session beans discover transaction outcome

Figure 8.23 shows a lifecycle diagram for a stateful session bean indicating
when each method of the SessionSynchronization interface is called.

Copyright © 2001, DevelopMentor Inc. 325


Module 8: EJB Declarative Transactions

client ca lls create(…) on home:


Class.newInstance()
setSessionContext()
container passivates:
ejbCreate(…)
ejbPassivate()
does not
ready passive
exist
client ca lls re move(): client calls method and
ejbRemove() container activates:
ejbActivate()

tx ends:
client executes afterCompletion(false)
non-tx method
client or
executes beforeCompletion()
executing first method afterCompletion(true/false)
non-tx method in tx:
execution ends afterBegin() ready in tx

bean executes
tx method
executing
in tx tx method
execution ends

Figure 8.23: Lifecycle of a transaction-aware CMT stateful session bean

326 Copyright © 2001, DevelopMentor Inc.


Module 8: EJB Declarative Transactions

Summary
• Container uses interception to manage TX lifetime/scope
• Container plumbing starts, ends and propagates TXs
• Container plumbing enlists transactional resources
• Transactional objects can influence TX outcome
• Container can bracket and scope TX based on declarative attributes
capturing intent
• Bean can programmatically bracket and scope own TX

Copyright © 2001, DevelopMentor Inc. 327


Module 9

State Management

Copyright © 2001, DevelopMentor Inc. 329


After completing this module, you should be able to:
 understand the different data scopes
 understand how to use threads safely on a page
 understand how to use the HttpSession API
 understand the use of cookies in conversational state

330 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

Managing State in a Web Application


HTTP is a stateless, largely connectionless, protocol.
Because of this, managing conversational state in
web environment is problematic. This section
discusses the issues of state management in web
applications, and the help given to servlets by the
API.

Copyright © 2001, DevelopMentor Inc. 331


Module 9: State Management

Managing conversational state


HTTP is stateless

• Mostly connectionless
• No way of identifying which user request has come from
• Need an "out-of-band" technique to establish a conversation
• Cookies, URL re-writing most common techniques

332 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

HTTP is "logically" a connectionless protocol. While a single request and


response are performed connected, as soon as the response is received the
connection is broken. This means that one HTTP request is made independently
of another. When building web applications this leads to a problem: how does
the server know if a request is coming from a user it has seen previously? Take
the example of a shopping cart. A site requires a user to log on before
proceeding to other parts of the site. So, a user browses to the logon page and
logs on. When the user then browses to another page, how does the site know
that the user has logged on? Since the second (and subsequent) request is
independent of the original request, the site has no way of knowing who the
second request belongs to. The IP address is useless in this case because the
request could have come through a firewall or proxy, and the server may see
that address, not the address of the originating client.
To establish the identity of the client, some out-of-band technique is
needed, and several are possible. Typically, the client's state is held at the
server, and the client and server exchange some piece of data in every
message that can be used to identify the client. (Note that we could exchange
the data that the client owns in each message, which may work for small
amounts of data, but typically doesn't scale). On the first request to a site, the
server checks to see if the client is sending an identifier. If not the server will
create an identifier for that client, and associate that identifier with a data
store on the server. In it's simplest case the data store could be a hashtable,
keyed on the identifier, with the objects in the hash table holding the client
state. The identifier (typically called the session-id) has to be sent back to the
client. The client simply returns this session-id with each subsequent request to
the server. The session-id could be sent back in a hidden form field (if all of
our pages are form based), as an extension to the URL we are browsing to (this
is called URL re-writing or URL munging), or, most typically, as an HTTP cookie.
Figure 9.1 shows this in action. The client makes a request to the server.
The server creates a "session" (a place to hold the users state) and a session-id
(a cookie), the cookie is sent back to the client in the response. For each
subsequent request the client sends the cookie along with the request and the
server uses this cookie to look up and use this client's session state.

Copyright © 2001, DevelopMentor Inc. 333


Module 9: State Management

client 1. Initial client HTTP GET request web server


2. Session and
4. Client keeps 3. Server sends session-id session-id created
session-id and its
association with the
Book A
server
5. User browses to item ‘A’ page Book B
This will be sent back 6. User purchases item ‘A’
and forth in
subsequent messages
7. User browses to item ‘B’ page
8. User purchases item ‘B’

9. User goes to checkout

Figure 9.1: Using cookies to manage state

334 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

State is held at the server


Per user state

• HttpSession object
• Associated with a user session
• Typically with a cookie (name is jsessionid)
• HttpSession ses = req.getSession(true);
• <%@ page session="true" />
• session.setAttribute(name, value)
• <jsp:useBean name="..." class="..." scope="session"/>

336 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

While in the above example we used cookies to manage the session id, it is also
possible to use URL re-writing to do this. In URL re-writing all the URLs
returned to the client are "tagged" with the session-id. How this is done is up to
the server, but typically the session-id is added as a parameter. This means, for
example, an anchor tag would look like this <A
href="forward.jsp;jsessionid=59544452371402A7714884F3F213B1E5">Forward
to</A>. In the Servlet API the creation and management of the session state
and the session-id is done for you. The specification defines a class
HttpSession that abstracts away the use of sessions: this class works with
cookies if available or URL rewriting if cookies are disabled at the client.
Notice that whether a cookie or URL re-writing is used the session-id is always
called "jsessionid". This is mandated by the specification. Figure 9.2 shows the
key methods in the class.
void setAttribute(String name, Object value)
String[] getAttributeNames()
Object getAttribute(String name)
void removeAttribute(java.lang.String name)

long getCreationTime()
void setMaxInactiveInterval(int interval)
void getMaxInactiveInterval(int interval)
long getLastAccessedTime()

void invalidate()
boolean isNew()

String getId()
Figure 9.2: HttpSession class

Creating a session in a servlet is straightforward, in the doGet or doPost


method call request.getSession(). This method takes a single parameter,
a boolean. If the value is true, the call to getSession checks to see if the
user is associated with a session. If not, then an HttpSession object and a
session-id are created, and associated with the user. If a session already exists
then the call simply returns that session. Passing false stops the server from
creating a session if one doesn't exist. The call simply returns null in that
case. If you call getSession(true) you will always get an HttpSession
returned, you may need to initialise the session if it is new. To check for a new
session call session.isNew(). Figure 9.3 shows this standard idiom for using
sessions.

Copyright © 2001, DevelopMentor Inc. 337


Module 9: State Management

public void doGet(...){


// true creates a session if none exists
HttpSession session = req.getSession(true);
Email email = null;
if(session.isNew()) {
email = new Email(...);
// add values to the session
session.setAttribute("logon.isDone", email);
}else{
email = (Email)session.getAttribute("logon.isDone")
}
}
Figure 9.3: Using the HttpSession class

Data is stored in a session by calling the session.setAttribute() method.


This takes a name value pair where the value is a Java bean. Data can be
retrieved from a session by calling session.getAttribute(), which takes
the name of the bean to retrieve a reference to.
In JSP, accessing data in the session is done through the <jsp:useBean...
> tag, specifying "session" as the scope.

338 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

Session Lifecycle
Sessions don't last forever

• Check the session has just been created (isNew())


• Have a server specified timeout period
• Can also invalidate the session (invalidate())
• Session object will release all its references

340 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

As we saw above, a session is created when a servlet calls


request.getSession(true), but when do sessions end? Typically, a users
session ends when they logout of your application, but in a web environment it
is simply impossible to make a user logout of the application. You could still
add a logout page, so that if the user did logout the session could be
terminated. You terminate a session by calling session.invalidate().
However, suppose the user never goes to the logout page. In that case you'd
like the session to timeout after some period of inactivity, and this is what
HttpSession does. HttpSession has an associated inactivity period after
which the session object is no longer useable, you can set this
programmatically (setMaxInactiveInterval()) or via the deployment
descriptor (in the <session-timeout> element). The value is set in seconds,
setting the value to -1 causes the session to never expire. Once the session
times out, it releases all the references it is holding

Copyright © 2001, DevelopMentor Inc. 341


Module 9: State Management

Session Events
Sessions fire events

• When sessions start and end


• Object may need to acquire resources
• Object may need to release resources
• Object signifies interest by implementing HttpSessionBindingListener

342 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

Once you store an object in a session, you pretty much lose control over its
lifecycle. Unless the user logs out, you have no idea when the session ends.
This may not be important to you, but if the object is holding references to
system resources, you need to know when the session expires so that you can
free up those resources. To allow you to allocate and free resources when
objects are added to a session, the HttpSession class fires events at session
start and session end. These events are fired at objects that are part of the
session, and only objects that care about the events get called. To let the
session know that an object wants to be told about session start and end
events, the object implements the HttpSessionBindingListener
interface. This interface has two methods, sessionBound and
sessionUnbound. sessionBound gets called when the object is added to
the session and sessionUnbound when the session becomes invalid. Figure
9.4 shows an example of using HttpSessionBindingListener
public void doGet(HttpServletRequest req,
HttpServletResponse res){
HttpSession session = req.getSession(true);
session.setAttribute("UserLogon", new UserLogon());
}

class UserLogon implements HttpSessionBindingListener{


public void valueBound(HttpSessionBindingEvent evt)
public void valueUnbound(HttpSessionBindingEvent evt)
// other methods
}
Figure 9.4: Using the HttpSessionBindingListener interface

Copyright © 2001, DevelopMentor Inc. 343


Module 9: State Management

Session Lifetime
When does a session end

• Web users do not generally log out of their web applications


• Typical web server applications deal with this problem by using inactivity
time-outs
• How long is long enough?
• Until session times out, shared server resources are being consumed
• This manages the in-memory lifetime of the session
• Cookies can also expire
• HttpSession cookies have a timeout of zero (in memory only)
• Expired cookies will not be sent to the server

344 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

One last thing to think about, the lifetime of the session state held at the
server is orthogonal to the lifetime of the cookie sent to the client. If you are
using HttpSession, then the session will last until the time the user last
"visits" the application, plus the inactivity period. The cookie sent back to the
client however has a timeout period of 0, which means that the cookie is
destroyed when the browser exits. There are two implications here: if the user
visits a web site and starts a session, the server sends back a cookie. If the user
now closes then re-starts the browser and re-visits the web site, the cookie will
have been lost and a new session will be created. The "opposite" is also true. If
a client visits a web site and starts a session, the browser will hold onto the
cookie. If the user now goes to lunch, and comes back an hour later, the cookie
may still be sent, but the session will have timed out at the server, so again a
new session will be created.

Copyright © 2001, DevelopMentor Inc. 345


Module 9: State Management

Distributable Sessions
Managing state in the face of server crashes

• Use <distributable> deployment setting


• Dynamic load balancing and fail-over schemes now possible
• Can keep session state on another server
• Session state can be distributed to all servers within farm
• Extra work to manage state
• Limitations on what can go into session object
• ServletContext is no longer a singleton

346 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

So far we have discussed concrete use of sessions and the session API. We now
want to discuss session management as it effects the configuration of your
application. Sessions hold user state, and the model we've been discussing up
until now is one where the user state is held in memory on a web server. This
leads to two problems. The first problem happens when the web server is part
of a server farm. In that case, if the session state is in memory on a web
server, the user's requests must always go to that server. I.e. the user is pinned
to the server, so load balancing must be done on a per user basis, not a per
request basis.
The second problem, which is much worse than the first, arises if the web
server holding the in-memory state crashes, or the client can no longer reach
the server because of some network failure. In this case the client can keep
browsing to the site (it's a web farm, so the client's next request will be routed
to another server in the farm) but the client will have lost their session data,
and will have no idea why. Scale this up from one client to a hundred thousand
clients and there is a major problem with keeping state on a single server.
Figure 9.5 shows this.

Copyright © 2001, DevelopMentor Inc. 347


Module 9: State Management

web server 1

session
state
client
1

web server 2

Figure 9.5: Session state held on a single server

There are many ways to solve this issue, but they follow one of two idioms,
either store the state on dedicated server (such as a database server), which
has fail-over and replication, or distribute the state around multiple servers in
the server farm. There are also variations on the themes, such as giving each
server a "buddy" that holds a copy of everything the main server is doing, and
that is able to step in if the primary server fails. Figure 9.6 shows this idea.

348 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

web server 1

client 2 other server


1

session
state

web server 2

3 4

Figure 9.6: Session state held on a single server

The servlet specification doesn't mandate any particular scheme. Instead the
specification allows vendors to innovate. If an application wants its state to
possibly live on more than one server, that application can mark itself as
<distributable> in the deployment descriptor. When a server deploys a
<distributable> application, it is free to manage state anyway it sees fit.
Marking an application as <distributable> does have implications for your
code, however. For example the ServletContext is no longer a singleton,
since an application may now be spread over multiple VMs, but more
importantly, there are limitations on what can go in the HttpSession object.
If you are using a Servlet 2.2 container and the application is marked as
<distributable> then only Serializable objects can be placed into the
HttpSession. This makes sense, as the container has to get the session data
from one VM to another, and Java serialization seems a natural way to do this.
However if you are using a Servlet 2.3 compatible container, then things
change slightly, as well as Serializable objects, the container may allow
other object references (such as EJB references) that the container
understands, and that the container is able to migrate from VM to VM--you will
need to check your container documentation to see what is allowed.

Copyright © 2001, DevelopMentor Inc. 349


Module 9: State Management

Cookies
Most common technique for managing sessions

• Two headers Set-Cookie and Cookie


• Set-cookie: userid=922816702375114053;
• Cookie: userid=922816702375114053
• Cookie contains name: value pairs
• Associated with a domain
• www.amazon.com
• .amazon.com
• Servlet API has a Cookie class

350 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

We've spoken throughout this chapter about cookies and how they are used by
HttpSession, but what are cookies? Cookies are data that are sent in headers
as part of an HTTP request response pair. A server establishes a session by
sending the client a Set-Cookie header. This header will contain two types of
data, server specific (the cookie itself) and standard (as defined by the
specification). The user specific information is in the form of a name=value
pair (as shown above). If a client has cookies enabled, then the client responds
by sending a Cookie header in the next HTTP request. The client cookie will
contain the same name: value pair sent by the server. Cookies can be
associated with a domain, and a path on that domain. This allows servers to
tune their cookies to certain applications on that server.
The use of cookies in Servlets is abstracted away by the Cookie class. The
class is shown in figure 9.7. Notice that you can create cookies with a name,
and then associate them with a value. Servlet created cookies can be
associated with a path and a domain, and cookies have a max age. It's the
ability to set the maximum age of cookies using the Cookie class that
distinguishes these cookies from cookies created by the HttpSession class
that have a fixed timeout of zero. This means that if you want to create
sessions that span a browser's lifetime, you have to use the Cookie class and
not the HttpSession class. Notice, however that if you use the Cookie class
you get no help with session management. Such things as storing state at the
server, and server-side session time outs are all left to the developer.
public void setComment (String purpose);
public String getComment ();
public void setDomain (String pattern);
public String getDomain ();
public void setMaxAge (int expiry);
public int getMaxAge ();
public void setPath (String uri);
public String getPath ();
public void setSecure (boolean flag);
public boolean getSecure ();
public String getName ();
public void setValue (String newValue);
public String getValue ();
public void setVersion (int v);
public int getVersion ();
Figure 9.7: The Cookie class

Using the cookie class is quite straightforward, as 9.8 shows. You create a
cookie object, set the appropriate values, and then add the object to the
response. The addCookie method will build the appropriate header. Getting
the cookie from the request involves slightly more work, as the request could

Copyright © 2001, DevelopMentor Inc. 351


Module 9: State Management

contain more than one cookie. The getCookie call returns an array of cookies
that have to be parsed looking for the right cookie.
public void doGet(HttpServletRequest req,
HttpServletResponse res){
String user = getCookieValue("user", req.getCookies());
if(user == null){
user = req.getParameter("user");
Cookie ckie = new Cookie("user", user.toString())
ckie.setMaxAge(30*24*60*60); // 30 days
res.addCookie(ckie);
}
}
String getCookieValue(String name, Cookies[] cookies){
String value = null;
if(cookies != null) {
for(int i; i < cookies.length; i++) {
if(cookies[i].getName().equals(name))
value = cookies[i].getValue();
}
}
ret value;
}
Figure 9.8: Using Cookies

352 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

Managing State in the Face of Threads


Web servers typically dispatch requests on multiple
concurrent threads, which means that servlets must
be written to be thread safe. This section examines
thread safety in servlets, and how to achieve it.

Copyright © 2001, DevelopMentor Inc. 353


Module 9: State Management

Servlets and Threads


Web servers are multi-threaded

• Container will typically load one instance of a servlet


• doPost and doGet will be re-entered
• Servlets must be aware of multi-threading issues

354 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

When a request comes into a web server, the server will typically dispatch that
request on one of many threads, so that as requests arrive they get dispatched
on an available thread. This means that web servers are multi-threaded and
that we must write our servlets to be thread safe. There is no getting away
from this: servlets and JSPs must be written in a thread-safe manner. Figure
9.9 shows the various scopes of data that an application in a web server will
use. Some data is "naturally" thread safe and no special steps need to be taken
to protect access to that data. Some data however may be accessed by
multiple threads at the same time, and care must be taken when using that
data.

Statics
class foo{
foo{
private static int a;

Instance (member)data
class foo{
foo{
private int n;

Method Parameters
void bar(int
bar(int a, int b){
}

Local (Stack)
void quux(){
quux(){
int l;

Sessions
HttpSession session =
req.getSession
req.getSession();
getSession();

ServletContext
getServletContext(
getServletContext(
).setAttribute
).setAttribute(...)
setAttribute(...)

Figure 9.9: What data is thread safe in a servlet

In many cases it is obvious what does and does not need protecting. Local
variables are thread safe: a thread has only one stack and local variables live
on that stack, only one thread can be touching those variables at any given
time. Method parameters are generally safe for the same reason. The caveat in
both these cases is that the caller of the method has not handed out a
reference to these objects to another thread before making the call. In the
case of servlets, the two parameters we really care about are the
HttpServletRequest and the HttpServletResponse. These are
guaranteed to be thread-specific, i.e. they will be available to only one thread.
Other objects are also obviously not thread safe--static data and instance
data fall into this category. Web servers will create a single instance of a
servlet for use by all clients. This instance will be called on multiple threads
concurrently, which means that any static or instance data will also be
accessed by multiple threads. Actually, in servlets this isn't such an issue. What
does instance state mean to a servlet? It's not per client or per request, or per
application or per anything. This means that instance data members are not
used very often.
The other two entries in figure 9.9 are for HttpSession and
ServletContext. The ServletContext is an object shared by all users of
the application, so any access to ServletContext must be thread safe. But
what about HttpSession? An HttpSession is private to a user, users

Copyright © 2001, DevelopMentor Inc. 355


Module 9: State Management

typically only make one request at a time, that request would complete before
the next request was made, which implies that an HttpSession would only
ever be accessed by one thread at a time. However, that isn't the case. A user
can make multiple concurrent requests to the same application, for example,
having multiple browser windows open and refreshing each window, or simply
having a window that consists of a frameset and multiple frames. In either of
these cases multiple concurrent request could be sent to the application for a
single user, which means multiple threads and concurrent access to the
HttpSession object.

356 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

Protecting State
Some data must be protected from concurrent access

• Can use Java's synchronization


• Shouldn't just synchronize methods which effectively makes the servlet
single threaded
• Protect only what is necessary
• Use synchronized blocks instead, to protect only what is necessary
• Keep time in any synchronized code block short
• Warning: Contention #1 enemy of scalability

358 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

Protecting state in Java is easy in theory but more difficult in practice. Java
has the synchronized keyword that can be used to synchronize methods or
blocks of code. There is one golden rule to remember: Only synchronize what
you have to! Contention of any sort will harm scalability; contention of threads
is no different. For example it may be worth investing time in defining read
locks and writes locks to limit the amount of contention you have, but one
thing you must do is keep time in any lock as short as possible.

Copyright © 2001, DevelopMentor Inc. 359


Module 9: State Management

Protecting Application State


Application scope data must be protected from concurrent access

• Applications have shared state


• Data is shared in the ServletContext
• Multiple threads can access application state
• Therefore access to ServletContext must be synchronized

360 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

As we said above, the ServletContext is a shared object, and access to this


object must be managed. There are many choices when protecting the data in
the servlet context. Figure 9.10 shows the simplest option: wrap all access to
the ServletContext in a synchronized block. Be aware this may not be
the best way to synchronize access to the data. For example, if the reference
that is stored in the ServletContext is constant (i.e. the object being
reference is always the same instance), but the data in the object may change,
then accessing the servlet context outside of a synchronized block is fine, so
long as all access to the object is done inside a synchronized block.
ServletContext ctx = getServletContext();
org.w3c.dom.Document xmlDocument;
synchronized(ctx)
{
xmlDocument = (Document)ctx.getAttribute("DOM");
// other 'application' access code
}
Figure 9.10: Protecting Application State

Copyright © 2001, DevelopMentor Inc. 361


Module 9: State Management

Protecting Session State


Session state is also shared

• A client could make many simultaneous requests


• Many browser windows open
• Frames within a frame window
• Each request would be in the same session
• Multiple threads accessing session state
• Access to session MUST be synchronized

362 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

Figure 9.11 shows how to protect the HttpSession object. Note that the
same caveats apply as accessing the ServletContext.
String strUserName = req.getParameter("userName");
User user = new User(strUserName);
HttpSession sess = req.getSession(true);
synchronized(sess)
{
sess.setAttribute("user", user);
// other session access code
}
Figure 9.11: Protecting Session State

Copyright © 2001, DevelopMentor Inc. 363


Module 9: State Management

javax.servlet.Singlethreadmodel
SingleThreadModel

• marker interface tells container to use a pool of servlet instances


• Guarantees only one thread per servlet instance
• "Naively" thread safe
• Session/ServletContext not automatically serialized
• Containers free to abandon scalability

364 Copyright © 2001, DevelopMentor Inc.


Module 9: State Management

The Servlet API contains an interface called


javax.servlet.SingleThreadModel. This is a signature interface (i.e. it
has no methods to implement), which, when implemented by a servlet marks
that servlet as single threaded. What does this mean? Typically a web server
will create a single instance of a servlet to handle all requests made to that
servlet (remember that it is possible to have multiple instances of the same
servlet, based on the <servlet-name> in the deployment descriptor), which is
one of the reasons why servlets have to be thread safe. However, when a
servlet implements javax.servlet.SingleThreadModel the container
must only allow a single thread to call this servlet at any one time. On the
surface this seems like a great idea, no more worries about multi-threaded
access, as the servlet is single threaded. Unfortunately this is not true.
javax.servlet.SingleThreadModel introduces issues without solving
anything. If you use javax.servlet.SingleThreadModel you immediately
cause scalability problems in your applications. You only allow a single thread
through that servlet at any one time, and the servlet becomes a bottleneck.
Containers are free to create many instances of a
javax.servlet.SingleThreadModel servlet to ease this problem, but
many do not. A bigger issue, though, is that a
javax.servlet.SingleThreadModel servlet still has to care about
threads. If a javax.servlet.SingleThreadModel uses either the
ServletContext or an HttpSession, then access to these objects must still
be done in a thread-safe way. javax.servlet.SingleThreadModel only
guarantees this instance of the servlet is single threaded, it doesn't stop all the
threads in the server, so other servlets, or other instances of this servlet could
(and will) access ServletContext and HttpSession. Don't use
javax.servlet.SingleThreadModel, it comes with a high price for no
benefit!

Copyright © 2001, DevelopMentor Inc. 365


Module 9: State Management

Summary
• HTTP is largely connectionless
• State management has to be added
• Cookies typically used to do this
• HttpSession class keeps per-user state
• Servlets are multithreaded--you must protect against concurrent access to
state

366 Copyright © 2001, DevelopMentor Inc.


Module 10

EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 367


Using stateful and stateless EJB session beans

After completing this module, you should be able to:


 appreciate the role of stateless and stateful session beans

368 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

EJB Sessions
Sessions beans are the connection model to external
clients and are EJB's incarnation of the "processor"
to represent client logic running on a server. There
are two types of session bean that capture the two
common middle-tier programming paradigms--
stateless and stateful.

Copyright © 2001, DevelopMentor Inc. 369


Module 10: EJB Session Beans

Two bean types


Tasks and things

• Session beans represent transient processors


• Task-based logic running on a server
• Connection model to external clients
• Dedicated to one client at a time
• Model stateless or stateful techniques
• Entity beans represent persistent, shared entities
• Manipulated by sessions
• Transactions used for concurrency control
• Typically backed by tables in a [R]DBMS

370 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

There are two flavours of EJBs. Sessions beans are EJBs connection model to
external clients and are so named because they represent a "session" with a
particular user. Their methods represent task-based logic running on a server.
There are two types of session that represent the stateless and stateful
programming models. The stateless session bean represents a "processor"
object, dedicated to a single client for the duration of a single method call.
Because it may get reused by different clients across different method
invocations it holds no conversational state or volatile shared state across
method invocations. In this sense, it is similar to a database stored procedure
that runs in the middle-tier, in that it can encapsulate a use case, be executed
once and then reset. The stateful session bean represents an entire long-
running, client-server style session. It is dedicated to a single client for its
whole lifetime and therefore can hold client conversational state across
method calls. Sessions are essentially transient objects that don't outlive an
operating system process.
Entity beans, on the other hand represent shared/persistent/read-write data
cached in the middle-tier. If sessions represent business processes then entities
represent business objects that are manipulated by those business processes.
Because of its shared and read/write nature, an entity is manipulated under a
transaction to effect the concurrency control needed to keep its data
consistent. Entities are typically, although not necessarily, backed up by tables
in an [R]DBMS.
Sessions beans and entity beans will be explored in more detail in later
sections. The aim here is to show the process of building and deploying a bean,
regardless of its type. Given that session beans are designed to be used from a
client then we will develop one of these first.

Copyright © 2001, DevelopMentor Inc. 371


Module 10: EJB Session Beans

Stateless session bean ("processor" bean)


Like a traditional stateless TP component

• Lifetime defined by a single method on behalf of single client


• Bean instance "activated" at method start, "deactivated" at method end
• Bean instance may be pooled across activations
• Method provided "identity" via input parameters
• Manages persistent state (if any)
• Holds no conversational or volatile shared state across methods
• Lifecycle decided by container

372 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

The stateless programming model is exemplified by traditional transaction


processing (TP) systems. The client formulates a request that wholly identifies
some transacted operation to be performed on the server. The TP system
receives the request, starts the transaction, and "activates" some associated
component to service the request, providing it with the input parameters
passed in by the client. The component manipulates data, held in a persistent
store, under the control of the transaction. As it executes, the component
accumulates the data it needs as the operation progresses and when the
operation completes, it writes back any updated data before the component
itself is "deactivated". Component "activation" may mean a component has to
be created or it may mean it is obtained from a pool of identical looking
components. Component "deactivation" may mean the component is destroyed
or put back in the pool. As long as the component is in a prescribed default
state at activation time it doesn't matter. The key point is that no client-
specific conversational state or updated shared state is held in memory after
the transacted operation completes (thus the term "stateless") as this would
violate the transaction semantics of the system. The component is only
associated with the client that made the request while the operation is in
progress. The next time the component runs the same (or a different)
operation it may do so on behalf of a different client. An EJB stateless session
bean follows this model. It should never really have been called a session (in
this author's opinion). Sessions conjure up the idea that conversational state is
being maintained. An EJB stateless session bean is really a "processor" bean.
A stateless session bean has a remote interface that defines a collection of
methods, each of which represents the kind of stateless operation described
above. Another way of thinking about a stateless session bean is that it is
similar to a set of database stored procedures, in that it can encapsulate a set
of use cases, each of which can be executed once and then reset. From its
point of view, a stateless session bean's "lifetime" is defined by a single method
call--an instance of the bean class is "activated" to perform a task for a single
client in a single method call and then "deactivated" at method end. However,
the usage pattern for an EJB client is to obtain a remote reference, make many
method calls through the remote interface on the underlying object and then
release the reference. Does that mean the client has to amend its usage
pattern to repeatedly obtain a remote reference, make one method call and
release the reference, every time it wants to perform a stateless operation?
Here is where the EJB interception model proves really powerful. Recall it
provides a level of indirection between the caller and the bean class and that
the caller has a reference to the interposer and not the bean. This allows the
container to play tricks with the underlying bean class, activating and
deactivating it at will, while the client's reference remains valid. That is, while
the client holds a valid reference to the interposer it may be the case that an
instance of the bean class doesn't even exist or is not attached to the
interposer. The container can intercept a call to the bean in its interposer and
create or attach an instance of the bean class to it at the last minute, as

Copyright © 2001, DevelopMentor Inc. 373


Module 10: EJB Session Beans

required. When the method completes, the container can detach the instance
of the bean class from the interposer and optionally destroy it. The container
does just this for a stateless session bean.
The lifecycle of the stateless session bean instance is completely under the
control of the container and is illustrated in figure 10.1. The client needs to
obtain a reference to the remote interface on a stateless session bean in order
to make method calls on it. The way the client achieves this is to call
create() on the bean's home interface. However, the bean instance is not
needed until the client makes a method call at which point the container
attaches it to the interceptor ("activates" it) so it can execute the business
method. This means that the container needn't create the bean instance when
the client calls create() on the home interface, but could delay creating the
bean instance until the client made a method call. In fact, the container could
pre-create several bean instances before any client calls create() on the
home interface and hold them in a pool until they are needed. All that is
required is that an instance of the bean class be available when the bean needs
to be "activated" and that it should be in a prescribed default state. The bean
instance is only associated with a given client for the duration of the method
call. When the method is over and the container detaches the bean from the
interceptor ("deactivates" it), it could destroy the bean instance or put it back
in a pool to be reused by another client method call. Either way, the stateless
session mustn’t hold on to any conversational state or any updateable shared
state across activation/deactivation cycles (method calls) and must undertake
to put itself back into a default state upon deactivation (at the end of every
method call).

container creates when needed:


Class.newInstance()
setSessionContext()
ejbCreate()
does not in pool (no identity)
exist waiting to execute method call
container destroys:
ejbRemove()
Object.finalize()
client
executes
method method
execution
ends
Executing method on
behalf of some client request

Figure 10.1: Lifecycle of a stateless session bean

374 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

The EJB specification does not mandate pooling of stateless session bean
instances. It would be quite OK for a container to create the bean instance at
method call time, activate the bean, execute the method call, deactivate the
bean and destroy it. Most containers, however will pool stateless session beans
on a per-class basis. It makes no difference to the stateless session bean as its
behaviour must be the same with or without pooling. Pooling does amortize the
cost of destroying and re-creating objects over time but the saving really does
depend on the relative cost of creating/destroying the bean instance compared
to the cost of activating/deactivating it. Bean classes where the cost of
creation/deletion is negligible but the cost of activation/deactivation is
significant are not going to gain much from being pooled. If a container does
support pooling then the exact details of the mechanism and its configuration
are container-specific. For instance, the container could allow the
configuration of an initial pool size (pre-creation of bean instances), a
maximum pool size (throttling the number of concurrent requests by limiting
the number of active bean instances) and the behaviour when all pooled
instances are active (how long to block waiting for an instance to become
available before returning an error), etc. Throttling the number of concurrent
requests could be a valuable feature in scenarios where you could tell a priori
the maximum concurrency load before access to shared resources started to
degrade unacceptably because of locking cycles. The other alternative is to
allow all requests to execute concurrently and deal with the resultant locking
cycles with transaction timeouts.
So, the client's idea of when the bean is created and the bean's idea of when
it is created may be two different things. This explains why it is only valid for a
stateful session bean's home interface to have a single, no-arg create()
method. Every time the client calls a method on the bean, potentially it gets a
different bean instance. If the create() method of the home interface
accepted parameters, which bean instance would they apply to? Essentially,
calling create() on the home interface for a stateless session bean is just a
way for the client to get a reference to a remote interface through which it
can execute stateless methods--it isn't really creating anything (except a
method dispatching mechanism) and it certainly isn't initializing anything. A
stateless session bean's home interface has no "finder" methods because the
stateless session is essentially transitory. It's lifetime is defined by a single
method call and its transitory identity is passed in as input parameters to each
method call.
Calling remove() on a stateless session bean does nothing. It is completely
up to the container to decide when to destroy a stateless session bean instance
and when it does then the bean's ejbRemove() will be called by the
container.
It is worth noting that, counter to expectation, ejbActivate() and
ejbPassivate() are not called by the container when the stateless session
bean is activated and deactivated at the start and end of every method call.

Copyright © 2001, DevelopMentor Inc. 375


Module 10: EJB Session Beans

Rather, the start of the method is the implicit activation notification and the
end of the method is the implicit deactivation notification. The
ejbActivate() and ejbPassivate() methods are called for stateful
sessions beans as will be seen later.

376 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

Stateless session beans and JITA


Enforces best resource usage

• Not just about saving memory


• Forces acquire late, release early discipline for shared resources
• Programmers must be aware of this anyway!
• Assumes 1 client request == 1 method call

378 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

The "just-in-time-activation" (JITA) technique is practiced by the container in


an attempt to enforce best resource usage. Because the stateless session bean
instance is deactivated at method end it cannot hold conversational state or
volatile shared state. This means that its memory footprint (in comparison with
a stateful session) will be small, plus only a relatively small number are needed
in memory at any one time. Imagine the case where 1000 clients each hold a
reference to a stateless session EJB. Let us imagine there are a maximum of 20
concurrent requests at any one time. That means only 20 stateless session bean
instances are needed in memory simultaneously. Consider, however, the
JITA/pooling architecture has saved us the cost of 980 bean instances but at
the cost of 1000 container interposers and any container code necessary to
manage the JITA/pooling! The amount of extra memory taken by the container
must be as least as much as the memory saved on bean instances.
It turns out, though, that the main benefit of JITA is to make best use of
available resources in that it forces developers to use shared resources in a
disciplined way. By deactivating a stateless session bean instance at method
end the container is providing a none-too-gentle reminder that shared
resources (i.e. database connections and the data they provide access to)
should be released so they can be reused by others. This enforces the "acquire
late/release early" policy for scarce shared resources that ensures they can be
reused with less contention and that the total number of resources needed is
decided by the number of concurrent active requests, not per client.
However, the developer must appreciate the need for this programming
discipline anyway. JITA does nothing (except via transaction timeouts) to limit
the length of time that a method takes to execute. It would still be possible to
hold on to shared resources exclusively for far too long and increase the
amount of contention in the system.
Here is something else interesting to think about. The stateless programming
model assumes that one client request equates to a single method call and that
the overhead of activating the bean instance is incurred only once per request.
A client request via HTTP may not pan out this way. For instance, an operation
serviced by a Servlet or JSP may make five calls to a stateless session bean, in
which case the overhead of activating the bean instance is incurred five times
for a single client request. Resources must be re-acquired each time the bean
instance is activated and this may result in the operation taking longer than
necessary. Perhaps in this case it may be better to use a stateful session bean.

Copyright © 2001, DevelopMentor Inc. 379


Module 10: EJB Session Beans

Stateful session bean


More like an HTTP session

• Single client for whole lifetime


• Lifetime spans multiple methods
• Can hold conversation state across methods
• Identity maintained by connection/interposer
• Lifetime more in client's hands
• Transient/volatile

380 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

If a client wanted to build up conversational state using a stateless session


bean then it could. Two obvious techniques spring to mind. First, the client
could maintain the conversational state. The client would need to pass it in as
input parameters to the bean, and then adjust it according to the response.
Second, the server could maintain the conversational state. The stateless
session bean could mimic the way that cookies are used to maintain an HTTP
session on a web server, by forcing the client to send some identifier with
every call. The stateless session bean could detect a request from a client it
hadn't seen before, store the conversational state in persistent storage and
return its unique identifier to the client. The client would pass the identifier
back in with subsequent requests and the stateless session bean could
manipulate conversational state based on the id. This has the advantage of the
conversational state being stored persistently, which makes it more robust in
the face of client or server failure.
There is no need to go to this trouble however, as the EJB specification
supports both the stateless and stateful programming models. It recognizes the
need for the client to maintain conversational state on the server and provides
the stateful session bean to do just this. A stateful session bean instance is
more like what we instinctively think of as a session--an entire long-running,
client-server style session. For example, like an HTTP session managed on the
server using cookies. The advantage is that an EJB client, unlike a web client,
doesn't need to do anything special to maintain the identity of the EJB stateful
session. The EJB client merely creates a stateful session bean and the EJB
container maintains the identity based on the client's reference (connection) to
the bean's interposer. The stateful session bean is associated with a single
client for the whole of its lifetime which typically spans multiple method calls
and, for this reason, it is perfectly at liberty to hold conversational state in
memory on behalf of the client between method calls.
The lifetime of a stateful session bean is much more in the hands of the
client as is shown in figure 10.2. It is easy to see that because a stateless
session bean instance never gets reused across requests from different clients,
the container has no need to play the same tricks with the bean's lifetime. So a
stateful session bean instance has no need for JITA or pooling services. The
stateful session bean instance gets created when the client calls the create()
method on the bean's home interface. Because it is associated with a single
client, it makes sense for the client to be able to pass initialization parameters
at this time so the create() method can take parameters. The bean is now
ready to accept method calls from its client.

Copyright © 2001, DevelopMentor Inc. 381


Module 10: EJB Session Beans

client calls create(…) on home:


Class.newInstance()
setSessionContext() container passivates:
ejbCreate(…) ejbPassivate()
does not
ready passive
exist
client calls remove() client calls method and
or session times out: container reactivates:
ejbRemove() ejbActivate()

Client
executes
method
Method
execution
executing ends

Figure 10.2: Lifecycle of a stateful session bean

By default, a stateful session bean is transitory in nature. It will not outlive its
client unless the bean provides some protocol that allows the client to re-
create it with exactly the same state*. The end of its lifetime is decided either
by the client calling the bean's remove() method or releasing its reference to
the bean's remote interface, or by the server invalidating the bean upon some
client-inactivity timeout having expired. At this point, the bean is destroyed
and, by default, all its state is lost (see * above). If the client attempts to
access a stateful session bean after it has been destroyed it will receive a
java.rmi.NoSuchObjectException exception. The container may call the
bean instance's ejbRemove() when it is destroyed, although this is not
guaranteed.
As you can imagine, many stateful sessions could potentially take up much
memory on the server. Although the EJB specification doesn't mandate it, the
EJB server may support annotating a session bean class with an inactivity
timeout. That is, if the client doesn't call the stateful session back within that
time period then the container is at liberty to destroy the stateful session bean
instance. If the session inactivity timeout has not been reached (or there isn't
one) but the server is running out of memory then it may decide to "page" the
session to secondary storage to reclaim the memory it was using. Just before
this occurs the container calls the stateful session bean's ejbPassivate()
method. At this point it is the duty of the bean code to get itself ready to be
serialized by the container. This means logically "closing" transient/non-
serializable fields and setting them to null. For instance a socket, in the form
of a reference to a java.net.Socket is not serializable. The bean might
close the socket and store in a java.lang.String (which is serializable) the
host/portnumber connection endpoint information so that the socket
connection could be re-established upon re-activation of the bean. After
passivation the bean is not in a pool as, needless to say, it can only be re-

382 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

activated by the same client. If the client calls the bean again before the
inactivity timeout expires (if there is one ) then the bean will be re-activated
by the container de-serializing the bean into memory from secondary storage
and calling ejbActivate(). This is where the bean sets transient/non-
serializable fields back to their default and "re-opens" any previously closed
resources. For example, the bean might take the socket connection endpoint
information previously stored to the java.lang.String and use it to re-
create a reference to the java.net.Socket. The passivation/activation cycle
is transparent to the client. If a stateful session bean's inactivity timeout
expires while it is passivated it may be destroyed by the container without
calling the bean's ejbRemove().
Remember, by default a stateful session bean instance and its associated
state is volatile. If the session timeout occurs the bean is destroyed, if the
client calls remove() on the bean it is destroyed, if the client loses its
reference to the bean (including expected/unexpected shutdown of client) it is
destroyed, or if the server shuts down (expectedly or not) then the bean is
destroyed. It is not good practice to compose one logical session out of a
number of stateful session beans as any one of them may get destroyed,
leaving the session state incomplete.

Copyright © 2001, DevelopMentor Inc. 383


Module 10: EJB Session Beans

Stateful session bean handles


Used to keep stateful session beans alive across client invocations

• Like persistent cookies


• EJBObject.getHandle() yields serialized reference
• Handle.getEJBObject() yields access to same stateful session bean
• Handle useless if bean destroyed
• Application-level "cookies" can be used to implement persistent stateful
session

384 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

There is one way that a stateful session bean instance can be kept alive across
client invocations. In a web environment, persistent cookies can be used to
maintain a session across client invocations. When a client receives a persistent
cookie, it stores it away somewhere and associates it with the "domain" it came
from. Then, at a later date when sending a request to the same "domain" the
client re-presents the cookie and the server can identify the session. Stateful
session bean's have their own representation of a persistent cookie called a
handle. If the client calls EJBObject.getHandle() on a stateful session
bean it causes the container to hold an extra reference on the bean instance
and pass back a serialized javax.ejb.Handle reference containing
addressing/type information. The client can then save the handle, give up its
reference on the bean and close down. At a later date the client can use the
previously saved handle to re-hydrate a reference to the same bean using
Handle.getEJBObject(). Figure 10.3 gives some more detail. Of course,
the handle to the stateful session bean is useless if it is destroyed via
remove(), session inactivity or server shutdown. As mentioned, stateful
session beans can be made persistent with the correct level of application-level
"cookie" management.
CartHome ch=(CartHome)ctx.lookup("CartHome");
Cart c=ch.create(2001);

Order o = new Order();


o.putItem(30);o.putAmount(1);
c.addOrder(o);

ObjectOutputStream oos = new ObjectOutputStream(


new FileOutputStream("cart.ref"));
Handle h = c.getHandle(); oos.writeObject(h);
...
// Client ends

// New client invocation


...
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("cart.ref"));
Handle h = (Handle)ois.readObject();

Cart c = (Cart)h.getEJBObject();
Order o = new Order();
o.putItem(10); o.putAmount(2);

c.addOrder(o);
c.checkOut();
Figure 10.3: Example use of stateful session bean handles

Copyright © 2001, DevelopMentor Inc. 385


Module 10: EJB Session Beans

Appropriate use of session beans


Which access protocol to use?

• RMI is good for stateful sessions


• RMI is bad for load-balancing stateless sessions
• HTTP is good for load-balancing stateless sessions
• Load-balanced HTTP is bad for stateful sessions
• HTTP has other advantages too...

386 Copyright © 2001, DevelopMentor Inc.


Module 10: EJB Session Beans

Let's think about what happens if the client uses RMI to access session beans.
An RMI connection lasts as long as a client holds a remote reference to the
remote object. All the time a client holds a reference to a session bean then
the requests are sent back down the same channel to the same process on the
same server. This makes perfect sense for stateful session beans as they are
tied to their state held in memory so requests must go back to the same
process on the same machine. This makes no sense for stateless session beans.
Logically, they should not be tied to a particular machine as they lose their
state at the end of every method. But they are because the client holds a long-
lived connection on them. It would be nice to be able to load balance
aggressively for stateless session beans on a method-by-method basis. Most
load balancing software makes a decision about which server to route a client
to when the client requests a connection establishment. For an EJB object that
equates to calling create(), or something like it, on the bean's home
interface. The client could open and close a connection by brute force for
every method call to stateless session bean but that would break the client-
programming model. It is possible that a particular EJB server vendor may
provide cluster-aware stubs/skeletons that load balance on a per-method call
basis but this is not part of the EJB specification and could not be relied upon.
One other solution to this problem would be to use HTTP as the protocol to
access stateless session beans. After all, it is a stateless protocol that typically
keeps connections open for only one request/response cycle. It also has other
benefits such as it goes through firewalls more easily than RMI, it is more
pervasive than RMI and arguably it is simpler than RMI. If the client were to
insert HTTP between the client and the EJB session and represent each method
call as an HTTP request/response pair, then it would be possible to load
balance on a per-method basis. Servlets/JSPs could be used as the glue on the
server side to handle the incoming HTTP request, call the local stateless
session bean and pass the results back in the HTTP response. Stateful session
beans don't fit well into this model as, without some kind of cluster-aware
session support from the EJB server vendor (again, not part of the EJB
specification) the stateful session bean must be tied to a single machine
anyway.

Copyright © 2001, DevelopMentor Inc. 387


Module 10: EJB Session Beans

Summary
• Stateless session beans represent procedural model
• Stateful sessions represent conversational model

388 Copyright © 2001, DevelopMentor Inc.


Module 11

XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 389


After completing this module, you should be able to:
 define the term "Web Service"
 explain the role of XML in Web Services
 understand how XML Schemas enable typed communication
 describe how XML messaging (SOAP) works
 use WSDL to describe Web Services
 understand how to use UDDI to publish a Web Service
 explain how to use UDDI to discover a Web Service

390 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Web services
XML has become the de facto format for
representing data and information for exchange
between agents and software components. Web
Services use XML messaging to transform the way
the web is used.

Copyright © 2001, DevelopMentor Inc. 391


Module 11: XML-based Web Services

What is a web service?


Programmable component accessible using standardized XML messaging
over an Internet protocol

• Collection of operations defined by one or more messages


• Consumers only need create/consume such messages
• Ushers in new model for the web
• Other XML-related technologies important
• XML Schemas for common types
• SOAP for common messaging protocol
• WSDL for common service description
• UDDI for common service publishing/discovery

392 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Most of us are used to browsing sets of related documents on the web.


Typically, requests are manually initiated using HTML forms and the data
returned from any query is HTML and is only fit for displaying. The data cannot
be interpreted and used in any meaningful way. Web Services are ushering in a
new way of using the web.
A Web Service is a programmable component, designed for software
consumption rather than human consumption that is accessible using
standardized XML messaging over an Internet protocol such as HTTP. A Web
Service interface defines a collection of operations, each of which is defined by
one or more messages. Consumers of the Web Service can be implemented on
any platform in any programming language, as long as they can create and
consume the messages defined for the Web Service interface. Moreover,
because XML messages are used to communicate, intelligent agent software
can automatically enter into a transaction with the Web Service and interpret
the results it receives.
XML-based messaging is not enough on its own. As well as using XML as the
standard way to represent data, many Web Services will need to describe XML
data types as part of a type-safe interface, and this is where XML Schemas
come in. The Simple Object Access Protocol (SOAP) defines a protocol for XML-
based message exchange. It specifies a common, extensible message format,
rules for how to represent data types as XML and a convention for representing
remote procedure calls over HTTP. The Web Services Description Language
(WSDL) is an XML-based contract language that allows a Web Service interface
to be defined in enough detail so that software can be built to interact with it.
Finally, Universal Description, Discovery and Integration (UDDI) specifies a
mechanism for Web Service providers to advertise the existence of their Web
Services and for Web Service consumers to locate Web Services of interest.

Copyright © 2001, DevelopMentor Inc. 393


Module 11: XML-based Web Services

Universal types
XML Schemas are both an intrinsic type system for
XML as well as a language for expressing user-
defined types. A Web Service can use XML Schemas
to expose its type system to the outside world.

Copyright © 2001, DevelopMentor Inc. 395


Module 11: XML-based Web Services

What is XML Schema?


Provides a type system over the structured format of XML

• Schema type system rich enough to handle most common type systems in
use
• Schema types are universal--if XML is "portable data" then XML Schema is
"portable types"
• Schema processors add reflection capabilities to the Infoset
• Schema compilers will eventually eliminate the need for low-level XML
coding
• Schema compilers will turn schema types into programmatic types and vice
versa

396 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

XML provides a standard representation for data. It has a concrete transfer


syntax, called XML 1.0 + Namespaces, that is used to transmit and store XML-
based information no matter what system or technology generated the
information. It also has an abstract data model called the XML Information Set
(or Infoset) that describes the entities and relationships of an XML document in
syntax-free terms. Thus XML can be used to model virtually any kind of data
and share it with others. The relationship between the Infoset and XML 1.0 +
Namespaces is shown in figure 11.1.
Document : http://www.develop.com/roster.xml
Element : {urn:dm:people,student}
Element : {null,name}
Characters : Kevin Jones
XML Infoset
(Abstract model)
Element : {null,age}
Characters : 39

XML 1.0 + Namespaces <?xml version=‘1.0’ ?>


<ns:student xmlns:ns=‘urn:com:dm:people’>
(Concrete syntax)
<name>Kevin Jones</name><age>39</age>
</ns:student>

Figure 11.1: The XML Infoset

The key to making XML truly useful to software developers is the XML Schema
language because it provides a type system over the structured format of XML.
If XML is considered "portable data" then XML Schemas should be considered as
"portable types" as the XML Schema language has been embraced by virtually
every major XML vendor organization. The XML Schema specification became a
proposed recommendation (PR) of the World Wide Web Consortium (W3C) in
March 2001. This version of the schema language is identified by the
http://www.w3.org/2001/XMLSchema namespace URI. Previous versions of
the specification are identified by a namespace URI with earlier years, and it is
possible you may encounter software that has not been updated to support the
current specification.
Schema-aware processing software adds reflection-like capabilities to XML.
As shown in figure 11.2, the post-schema-validation (PSV) Infoset is adorned
with type information that makes every element's and attribute's underlying
type name and definition available to software that consumes it. This allows
software to dynamically discover type information as the XML-based data is

Copyright © 2001, DevelopMentor Inc. 397


Module 11: XML-based Web Services

consumed. Additionally, a schema-aware XML parser will validate that the


incoming text stream contains XML that adheres to the schema for the
corresponding namespaces found in the document. This ensures that only valid
information is processed by downstream components.
Document : http://www.develop.com/roster.xxml
ml
Element : {urn:com:dm:people,Person}, {urn:dm:people,student}

Post-Schema Element : {schema-ns,string}, {null,name}


XML Infoset string : Kevin Jones
(Abstract model)
Element : {schema-ns, double}, {null,age}
double : 39.0

<?xml version=‘1.0’ ?>


<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:tns=‘ urn:dm:com:people' targetNamespace='urn:com:dm:people'>
<xsd:complexType name='Person' >
<xsd:sequence>
<xsd:element type=‘xsd:string' name=‘name'/>
XML Schema <xsd:element type= ‘xsd:double' name='age'/>
</xsd:sequence>
</xsd :
complexType >
<xsd:element type= ‘tns:Person' name= ‘
student'/>
</xsd:schema>

Figure 11.2: The post-Schema XML Infoset

The syntactic relationship between an XML Schema document and the XML
instance document it describes is shown in figure 11.3. A schema document
describes types in a single namespace as defined by the targetNamespace
attribute of the schema element. An instance document can make a link
between the namespaces it uses and the schemas that define their contents,
using the schemaLocation attribute from the schema-instance namespace
http://www.w3.org/2001/XMLSchema-instance. This schema-instance
namespace contains XML Schema-related attributes that can be used in an XML
instance document (as opposed to an XML schema document).

398 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

<?xml version=‘1.0’ ?>


<ns:student xmlns:ns=‘urn:com:dm:people’
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation=‘urn:com:dm:people
http://www.develop.com/schemas/people.xsd‘>
<name>Kevin Jones</name><age>39</age>
</ns:student>

<?xml version=‘1.0’ ?>


<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:tns=‘urn:com:dm:people'
targetNamespace='urn:com:dm:people' >
<xsd:complexType name='Person' >
<xsd:sequence>
<xsd:element type=‘xsd:string' name=‘name' />
<xsd:element type=‘xsd:double' name='age' />
</xsd:sequence>
</xsd:complexType>
<xsd:element type=‘tns:Person' name=‘student' />
</xsd:schema>

Figure 11.3: XML Schema syntax

Figure 11.4 shows that XML schemas enable, amongst other things, smart
editors, code generation tools and general-purpose validators. It is important
to note that the XSD type system can be used to define types regardless of
whether or not the resulting representation is actually XML, or whether the
schema describing the types is used to validate the resulting representation if
it is XML. In particular, the relationship of a schema type to an XML instance
mirrors the relationship between a type and an instance in any programming
language. As the XML Schema language gains more momentum and is adopted
to describe universal types, more programming environments will provide
"schema compilers" that generate programmatic types based on schema types
(and vice versa), much as IDL compilers do today for CORBA-based systems. By
defining a mapping between an XML Schema-based type system and a
programmatic type system, one typically gets the [de]serialization of objects
and values for free. This concept is illustrated in figure 11.5 and figures 11.6
and 11.7 illustrate the synergy between, for instance, the Java type system and
the XML Schema type system.

Copyright © 2001, DevelopMentor Inc. 399


Module 11: XML-based Web Services

Automatic
COM Type
Serialization
Information

JVM Type
Remote
Information
Method
Invocation

Directory
Smart
Type XML Schema Editors
Information

Code
DBMS Type Generation
Information

.NET Type General


Information Purpose
Validators

Figure 11.4: The role of XML Schemas

Programmatic instance
XML Instance
(Object)

Programmatic type
Schema Type
(Class)
Figure 11.5: Bridging the type system

400 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

// package definition scopes the structured type


package com.develop.people
// Class definitions describe structured type
class Person {
String name;
short age;

}
// Variable declarations map types to symbolic names
com.develop.people.Person student;

// new operator instantiates a type,


// values specified through dot operator
student = new com.develop.people.Person();
student.name = “Kevin Jones";
student.age = 39;

Figure 11.6: Type description and use - Java

<schema xmlns='http://www.w3.org/2001/XMLSchema'
xmlns:tns=‘urn:com:dm:people'
targetNamespace='urn:com:dm:people' >
<!-- Complex type definitions describe structured types -->
<complexType name='Person' >
<sequence>
<element type='string' name=‘name' />
<element type='short' name='age' />
</sequence>
</complexType>
<!-- Element declarations map types to symbolic names -->
<element type=‘tns:Person' name=‘student' />
</schema>

<!-- Containing element instantiates a type,


values specified with contained elements -->
<ns:student xmlns:ns=‘urn:com:dm:people’ >
<name>Kevin Jones</name><age>39</age>
</ns:student>

Figure 11.7: Type description and use - XSD

Copyright © 2001, DevelopMentor Inc. 401


Module 11: XML-based Web Services

Schemas and programmatic type


XML schema type system is hierarchical and supports substitution and
inheritance

• Usual built-in types


• Simple types restrict built-in types or other simple types
• Apply to attribute values and text-only elements
• Complex types can use element/text children and attributes
• Allows more structured data types to be constructed
• Mapping XML schema type system to programmatic type system is non-trivial
• Some constructs not supported in schema
• Some constructs not supported in programming systems
• SOAP attempts to identify lowest-common-denominator

402 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

The schema type system is hierarchical and supports substitution and


inheritance. Two forms of type definition are supported: simple types and
complex types.
A simple type can only be represented as text and so apply to attribute
values and text-only elements. Each simple type is always a restriction of some
other simple type known as the base type. When a type restricts a base type it
means that it constrains the possibilities of the base type in some way such
that the new type is compatible with the base type. Figure 11.8 shows the
hierarchy of built-in types in the XML Schema language.

anyType all complex types

anySimpleType

string normalizedString
duration
token
dateTime
date language
NMTOKEN NMTOKENS
time
Name
year
month NCName
day
ID
yearMonth
IDREF IDREFS
monthDay
ENTITY ENTITIES
boolean
base64Binary
hexBinary nonPositiveInteger negativeInteger
decimal integer nonNegativeInteger positiveInteger
float long unsignedLong
double int unsignedInt
QName NOTATION
short unsignedShort
uriReference
byte unsignedByte

Figure 11.8: XML Schema simple types

Note that the root of the type system is anyType, the XML Schema moral
equivalent of java.lang.Object. It does not constrain its content in any
way--when applied to an element or attribute, it allows any content and, in the
case of an element, allows any attributes to be applied. If no type is specified
then anyType is used. The existence of anyType at the top of the type
hierarchy means that every other type definition is either a restriction or an
extension of some other type definition. When a type extends a base type it
means that it adds element or attribute content to the base type.

Copyright © 2001, DevelopMentor Inc. 403


Module 11: XML-based Web Services

New simple types are defined using the simpleType construct with facets
such as minExclusive, maxExclusive and enumeration used to specify
the constraints that restrict the value space of the base type. Figures 11.9 and
11.10 show examples of the definition and usage of simple types. Note that a
list of an existing type or a union of existing types are essentially just
restrictions of anyType.
<xsd:simpleType name='heightTokens' >
<xsd:restriction base='xsd:string' >
<xsd:enumeration value='tall'/>
<xsd:enumeration value='short' />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name='heightValues' >
<xsd:restriction base='xsd:short' >
<xsd:minExclusive value='0' />
<xsd:maxInclusive value='100' />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name='personHeight' >
<xsd:union memberTypes='tns:heightTokens
tns:heightValues' />
</xsd:simpleType>
<xsd:simpleType name='listOfNames' >
<xsd:list itemType='xsd:string' />
</xsd:simpleType>
<xsd:element name='heightToken' type='tns:heightTokens' />
<xsd:element name='heightValue' type='tns:heightValues' />
<xsd:element name='height' type='tns:personHeight' />
<xsd:element name='names' type='tns:listOfNames' />
Figure 11.9: Simple type definition

<folks xmlns:p='urn:com:develop:People'>
<p:heightToken>short</p:heightToken>
<p:heightValue>100<p:heightValue>
<p:height>short</p:height>
<p:height>36</p:height>
<p:names>Fred Wilma Betty Barney</p:names>
</folks>
Figure 11.10: simple type usage

Simple types are not always expressive enough. Complex types can be
represented using element children, character data children, and attributes.
This allows more structured data types to be constructed. New complex types
are defined using the complexType construct to specify a content model for a
given type of element, i.e. constraints on its children and attributes. Figure

404 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

11.11 shows an example. The "compositor" can either be sequence (all


particles in the compositor must appear in strict order of declaration), choice
(only one particle from the compositor must appear or all (all particles from
the compositor must appear but in any order). Particles of a complex type can
have occurrence constraints. The non-negative minOccurs attribute specifies
the minimum number of occurrences of a given particle and defaults to 1. The
maxOccurs attribute specifies the maximum number of occurrences of a given
particle and is either a non-negative integer or the string "unbounded" - its
value defaults to 1.
Group Definition

<xsd:group name='ProductTypes' >


<xsd:choice>

Group Reference
Group

<xsd:element name='produce' type='string' />


<xsd:element name='meat' type='string' />
</xsd:choice>
</xsd:group>

<xsd:complexType name='Product' >


<xsd:sequence>
<xsd:group ref='tns:ProductTypes' />
<xsd:sequence minOccurs='1' maxOccurs='unbounded' >
Group

Group

<xsd:element name='state' type=‘xsd:string' />


<xsd:element name='taxable' type=‘xsd:boolean' />
</xsd:sequence>
</xsd:sequence>
</xsd:complexType>

Figure 11.11: Complex type definition

As we have already seen, an element name can be bound to a type name with
an element declaration. Element declarations can be global or local. Global
element declarations map an element name in a namespace to a type and are
always children of xsd:schema. Local element declarations map an element
name in a given context to a type and appear as part of the content model for
a complex type. Because a local element declaration is typically more specific
than a global element declaration, whenever a global and local element
declaration are applicable then the local element declaration takes
precedence. This same rule is enforced for programming languages that
support the notion of global and local variable definitions, such as Java. By
default local element declarations are in no namespace. In figure 11.12,
age,height and name are in no namespace. This can be overridden for entire
schema using the elementFormDefault attribute and can also be specified
on a per declaration basis using the form attribute. Possible values are
"qualified" (element is in the target namespace) or "unqualified" (element is in
no namespace).

Copyright © 2001, DevelopMentor Inc. 405


Module 11: XML-based Web Services

<complexType name='Person' >


<sequence>
<element name='age' type='tns:personAge' />
<element name='height' type='tns:personHeight' />
<element name='name' type='tns:personName' />
</sequence>
</complexType>
<element name=‘student' type='tns:Person' />

Global and <p:student xmlns:p=‘urn:com:develop:People' >


<age>30</age>
in schema <height>short</height>
namespace <name>
<givenName>Barney</givenName>
Local and in <familyName>Rubble</familyName>
no </name>
</p:student>
namespace
Figure 11.12: Element declarations

A complex type can be derived from a simple type by extension or derived from
another complex type by extension or restriction. Restricted types restrict the
value space of the base type by providing tighter occurrence constraints and
narrower value spaces for simple elements and/or attributes. An example is
shown in figure 11.13. Extended types extend the content model and/or
attributes of the base type. The new content logically follows the content of
the base type. An example is shown in figure 11.14. An instance of a derived
type is always a valid instance of a base type. Additionally, however, an
instance document may provide explicit type information via the type
attribute from the schema-instance namespace
http://www.w3.org/2001/XMLSchema-instance. An instance of a type
derived via extension is never a valid instance of the base type. For this reason
the instance document must provide explicit type information via the type
attribute from the schema-instance namespace (or use element based
substitution which is beyond the scope of this discussion). Figure 11.15
illustrates.

406 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

<xsd:complexType name='vehicle' >


<xsd:sequence>
<xsd:element name='seats' type='xsd:short'
minOccurs='0' maxOccurs='1' />
</xsd:sequence>
</xsd:complexType>
<xsd:element name='transport' type='tns:vehicle' />
<xsd:complexType name='mannedVehicle' >
<xsd:complexContent>
<xsd:restriction base='tns:Vehicle' >
<xsd:sequence>
<xsd:element name='seats' type='xsd:short'
minOccurs='1' />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
Figure 11.13: Defining a derived type by restriction

<xsd:complexType name='wheeledVehicle' >


<xsd:complexContent>
<xsd:extension base='tns:Vehicle' >
<xsd:sequence>
<xsd:element name='wheels' type='xsd:short' />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
Figure 11.14: Defining a derived type by extension

<v:transport
xmlns:v='urn:com:develop:Vehicles'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:type='v:mannedVehicle' > <!-- xsi:type optional -->
<seats>4</seats>
</v:transport>
<v:transport
xmlns:v='urn:com:develop:Vehicles'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:type='v:wheeledVehicle' > <!-- xsi:type mandatory -->
<seats>4</seats>
<wheels>3</wheels>
</v:transport>
Figure 11.15: Using a type derived by restriction/extension

Copyright © 2001, DevelopMentor Inc. 407


Module 11: XML-based Web Services

Universal protocol
Protocols such as DCOM/IIOP/RMI don't satisfy the
needs of the web. SOAP combines XML and HTTP to
implement RPC-style communication that does.

Copyright © 2001, DevelopMentor Inc. 409


Module 11: XML-based Web Services

Simple Object Access Protocol


SOAP formalizes use of XML for messaging

• Adopted by W3C
• Defines message structure and processing rules
• Defines rules for encoding application data types
• Defines convention to represent RPC operation as 2 messages
• Complex type for request consists of in and inout parameters
• Complex type for response consists of inout and out parameters + result
• Possible to return fault message rather than result
• Possible to support message patterns other than request/response

410 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Simple Object Access Protocol (SOAP) 1.1 is a burgeoning industry-wide


specification that formalizes the use of XML for message-based communication
between heterogeneous systems. The specification defines the structure of a
message and how to process it, rules for encoding instances of application-
defined data types, and a convention for representing Remote Procedure Calls
(RPCs). At the moment, SOAP specifies HTTP as the communications protocol
used to transmit messages but in the future could also work with others, e.g.
SMTP. SOAP (or something like it) is needed because protocols such as
DCOM/IIOP/RMI don't satisfy the needs of the web (they are too complicated
and difficult to parse/construct, none are pervasive, they all mandate a
runtime and none are suited to passing through firewalls). One of the most
compelling things about SOAP is its simplicity. SOAP doesn't mandate a whole
lot--all you need is a TCP connection, a rudimentary understanding of the HTTP
protocol and the ability to parse and generate strings. SOAP promises to fulfill
the interoperability potential of XML by combining it with an equally
pervasive/simple communications protocol and finally bridging between the
current "islands" of component technologies like CORBA, Java and DCOM.
SOAP uses XML to describe a message. The structure of a message is defined
by SOAP and must comply with the SOAP schema,
http://schemas.xmlsoap.org/soap/envelope/, which defines formal
types for a Header, a Body and an Envelope. The Header conveys out-of-band
contextual information about how the message is to be interpreted and
processed, the Body is the serialized data to be transmitted (the payload) and
the Envelope is used as a container for "posting" the message. The structure of
the Header contents and the Body contents are decided by the communicating
applications--they contain instances of data types from application-defined
schemas. Figure 11.16 shows the format of a SOAP message. The namespace
URI for a SOAP message is the SOAP schema, the Envelope must be root
element of the message, the Body element is mandatory and the Header
element is optional. All extensions, if present, must appear in the Header
element and the optional mustUnderstand attribute distinguishes between
optional and mandatory extensions.

Copyright © 2001, DevelopMentor Inc. 411


Module 11: XML-based Web Services

<soap:Envelope
xmlns:soap=‘http://schemas.xmlsoap.org/soap/envelope/’
soap:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/’ >
<soap:Header>
<t:localeInfo xmlns:t=‘URI-for-LocaleInfo’ >
<country>us</country><lang>en</lang>
</t:localeInfo>

<t:dsig xmlns:t=‘URI-for-dsig’ env:mustUnderstand=‘1’>


<hash>38ae2f166abb2</hash>
</t:dsig>
</soap:Header>
<soap:Body>
<t:MyType xmlns:t=‘URI-for-MyTypes’ >
<field1>3</field1>
<field2>Bob</field2>
</t:MyType>
</soap:Body>
</soap:Envelope>

Figure 11.16: SOAP framing and extensibility

Although the contents of the Header and Body are decided by the application,
SOAP defines a set of encoding rules for serializing instances of application-
defined data types to XML data types. The rules are a generalization of
features found in the type systems of common programming languages. All the
built-in simple data types from the XML schema specification are supported and
new simple and complex types can be built, with particular rules for encoding
structures and arrays. Both pass-by-value and pass-by-reference semantics can
be represented. The encoding rules mandate "element normal form", meaning
that all components of constructed types are represented as elements not
attributes. The schema relating to the SOAP encoding style is
http://schemas.xmlsoap.org/soap/encoding/. Figures 11.17 and 11.18
show how a Java type translates to a type suitable for transmission in a SOAP
message.

412 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

package my.types;
class Point {
double x; double y;
};

Point point;
Point[] pointArray;

<xsd:schema xmlns:xsd='http://www.w3.org/2001/ XMLSchema'


xmlns:tns=‘urn:my:types ‘ targetNamespace ='urn:my:types'
xmlns:soap-enc=‘http://schemas. xmlsoap.org/soap/envelope/ ‘ >
<xsd:complexType name=‘Point’ >
<xsd:sequence>
<xsd:element name= ‘x’ type=‘xsd:double’ />
<xsd:element name= ‘y’ type=‘xsd:double’ />
</xsd:sequence>
</xsd:complexType >
<xsd:element name=‘point’ type=‘target:Point’ />
<xsd:element name=‘pointArray ’ type=‘soap-enc:Array ’/>
</xsd:schema>

Figure 11.17: SOAP-compliant types

point = new Point();


x=23;y=34;
pointArray = new Point[2];
pointArray [0].x=3; pointArray [0].y=4;
pointArray [1].x=5; pointArray [1].y=6;

<t:Point xmlns:t=‘urn:my:types’>
<x>23</x><y>34</y>
</t:Point>
<t:PointArray
xmlns:soap-enc=‘http://schemas. xmlsoap.org/soap/encoding/’
xmlns:t=‘urn:my:types’ soap-enc:arrayType =‘t:Point[2]’ >
<x>3</x><y>4</y>
<x>5</x><y>6</y>
</t:PointArray>

Figure 11.18: SOAP-compliant instances

A remote method signature call can be represented by a pair of types--one that


defines the method request, containing the input parameters, and one that
defines the method response, either containing the return code/output
parameters or exception information. The SOAP specification formalizes the
details of implementing RPC-style communication over HTTP. The SOAP
messages' bodies contain instances of types canonically named "function" and

Copyright © 2001, DevelopMentor Inc. 413


Module 11: XML-based Web Services

"functionResponse" as shown by figures 11.19 and 11.20. The HTTP messages'


content type is text/xml, and the HTTP response message uses status code
200 to indicate a successful method invocation or 500 to indicate an exception
or error. Errors are represented using a SOAP Fault element defined in the
SOAP schema, http://schemas.xmlsoap.org/soap/envelope/. Figures
11.21 and 11.22 illustrate. Notice how the operation is identified by a unique
SOAPAction URI to support fast dispatch/filtering. It is also possible to
support message patterns other than request-response, such as one-way (the
endpoint receives a message), solicit-response (the endpoint sends a message,
and receives a correlated message) and notification (the endpoint sends a
message).
double calcArea(Point p1,
Point p2) throws SomeException;

<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:tns=‘urn:my:types‘ targetNamespace='urn:my:types‘ >
<xsd:complexType name=‘calcAreaRequest’ >
<xsd:sequence>
<xsd:element name=‘origin’ type=‘tns:Point’ />
<xsd:element name=‘corner’ type=‘tns:Point’ />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name=‘calcAreaResponse’ >
<xsd:choice>
<xsd:element name=‘area’ type=‘xsd:double’ />
<xsd:element name=‘exception’ type=‘xsd:string’ />
</xsd:choice>
</xsd:complexType>
<xsd:element name=“calcAreaRequest“ type=“tns:calcAreaRequest” />
<xsd:element name=“calcAreaResponse“ type=“tns:calcAreaResponse” />

Figure 11.19: SOAP method signature

414 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Point p1 = new Point; p1.x=23;p1.y=34;


Point p2 = new Point; p2.x=24;p2.y=25;
Double ret = calcArea(p1,p2);

<soap:Envelope
xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Body> to server
<t:calcAreaRequest xmlns:t=‘urn:my:types’>
<origin><x>23</x><y>34</y></origin>
<corner><x>24</x><y>25</y></corner>
</t:calcAreaRequest>
</soap:Body>
</soap:Envelope>

<soap:Envelope
xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Body> from server
<t:calcAreaResponse xmlns:t=‘urn:my:types’>
<area>9</area>
</t:calcAreaResponse>
</soap:Body>
</soap:Envelope>

Figure 11.20: SOAP method call

POST /calcs/calcArea HTTP/1.1


Content-Type: text/xml
SOAPAction: http://develop.com/calcs#calcArea
Content-Length: nnnn

<soap:Envelope
xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Body>
<t:calcAreaRequest xmlns:t=‘urn:my:types’>
<origin><x>23</x><y>34</y></origin>
<corner><x>24</x><y>25</y></corner>
</t:calcAreaRequest>
</soap:Body>
200 OK
</soap:Envelope>
Content-Type: text/xml
Content-Length: nnnn

<soap:Envelope
xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Body>
<t:calcAreaResponse xmlns:t=‘urn:my:types’>
<area>9</area>
</t:calcAreaResponse>
</soap:Body>
</soap:Envelope>

Figure 11.21: Making a SOAP method call over HTTP

Copyright © 2001, DevelopMentor Inc. 415


Module 11: XML-based Web Services

HTTP/1.1 500 Internal Server Error


ContentType: text/xml
ContentLength: nnn

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Server Error</faultstring>
<detail>
<t:calcAreaResponse xmlns:t=‘urn:my:types’>
<exception>Rectangles with -ve sides not supported</exception>
</t:calcAreaResponse>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>

Figure 11.22: A SOAP fault

416 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Universal description
Web Services need to be well-described in order to
be generally usable. WSDL is an industry-standard
way to describe a Web Service interface and
deployment using XML.

Copyright © 2001, DevelopMentor Inc. 417


Module 11: XML-based Web Services

Web Services Description Language (WSDL)


XML vocabulary defining interface to web service

• Pioneered by IBM and MS, adopted by W3C


• Abstract definitions of types, messages, operations
• Mapped to particular data/message format, network protocol/address
• Related concrete endpoints form a service
• WSDL designed with extensibility in mind
• Any type description language, XSD is preferred
• Any data format, messaging protocol, network protocol
• Only SOAP 1.1, HTTP GET/POST or MIME bindings supported now

418 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Web services need to be described fully so that it is possible to build software


to interact with them--if possible, the description of a web service should be
such that software can be built automatically from it. What needs to be
documented? First, an interface, a collection of abstract operations grouped
together to form a type that may be implemented polymorphically. Second, a
protocol, the sequence of message exchanges that correspond to the
operations. Third, addressing information that would direct a caller to a
concrete implementation on the network. The Web Services Description
Language (WSDL) is an XML vocabulary that allows us to do just that. WSDL 1.1
is derived from work done by Microsoft and IBM and has been adopted by the
W3C.
Using WSDL, part of the interface definition is abstract, independent of, for
instance, a particular network protocol or messaging format. This abstract
definition then gets bound to a network protocol, data format, messaging
format and network address to form a concrete endpoint. The web service is
defined as a collection of related endpoints. Figure 11.23 shows the abstract
definitions and figures 11.24 and 11.25show the concrete definitions using soap
bindings.
<?xml version='1.0'?>
<wsdl:definitions name='calcArea'
targetNamespace='urn:my:definitions'
xmlns:tns='urn:my:definitions'
xmlns:t='urn:my:types'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'>

<!-- schema seen earlier -->


<wsdl:import namespace='urn:my:types'
location='http://develop.com/schemas/mytypes.xsd'/>

<wsdl:message name='calcAreaInput'>
<wsdl:part name='body' element='t:calcAreaRequest'/>
</wsdl:message>
<wsdl:message name='calcAreaOutput'>
<wsdl:part name='body' element='t:calcAreaResponse'/>
</wsdl:message>

<wsdl:portType name='calcAreaPortType'>
<wsdl:operation name='calcArea'>
<wsdl:input message='tns:calcAreaInput'/>
<wsdl:output message='tns:calcAreaOutput'/>
</wsdl:operation>
</wsdl:portType>
</wsdl:definitions>
Figure 11.23: WSDL abstract definitions

Copyright © 2001, DevelopMentor Inc. 419


Module 11: XML-based Web Services

<?xml version='1.0'?>
<wsdl:definitions name='calcArea'
targetNamespace='urn:my:services'
xmlns:tns='urn:my:services'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:defs='urn:my:definitions'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'>

<wsdl:import namespace='urn:my:definitions'
location='http://develop.com/wsdl/mydefinitions.wsdl'/>

<wsdl:binding name='calcAreaBinding'
type='defs:calcAreaPortType'>
<soap:binding style='rpc'
transport='http://schemas.xmlsoap.org/soap/http'/>
<wsdl:operation name='calcArea'>
<soap:operation
soapAction='http://develop.com/calcs#calcArea'/>
<wsdl:input>
<soap:body use='encoded'

encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</wsdl:input>
<wsdl:output>
<soap:body use='encoded'

encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
</definitions>
Figure 11.24: WSDL concrete SOAP definitions (part 1)

<wsdl:service name='calcAreaService'>
<wsdl:port name='calcAreaPort'
binding="tns:calcAreaBinding'>
<soap:address
location='http://develop.com/calcs/calacArea'/>
</wsdl:port>
</wsdl:service>
</definitions>
Figure 11.25: WSDL concrete SOAP definitions (part ii)

Each message element describes an abstract message communication and


each portType element ties operations to messages, thereby abstractly
describing each method. At this point, the types of both input parameters and

420 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

return values are specified, but the protocol to be used, the encoding, and
other details are still unspecified. Each binding element specifies the
protocol and encoding to be used for each operation. There can be several
different bindings pertaining to the same portType. There is only one SOAP
binding here. Each service element aggregates a set of related bindings,
each tied to a network address to provide a concrete endpoint.
As can be seen in 11.24 and 11.25, the WSDL binding and service
elements can be exactly specified with extensibility elements using another
XML grammar that allows concrete details like messaging formats, data
encoding formats, networking protocols and network addresses to be specified.
WSDL has designed these extensibility elements in although, at the moment,
XSD is the intrinsic (and preferred) language for type definition and the only
supported bindings describe how to use WSDL in conjunction with either SOAP
1.1, HTTP GET/POST or MIME.

Copyright © 2001, DevelopMentor Inc. 421


Module 11: XML-based Web Services

Universal discovery
UDDI defines a protocol for a rich Web service
information repository (or registry). Distributed
UDDI sites support publishing operations as well as
inquiry operations.

Copyright © 2001, DevelopMentor Inc. 423


Module 11: XML-based Web Services

What is UDDI?
Specification for distributed Web-based information registries of Web
services

• Joint Microsoft, IBM, and Ariba development


• UDDI itself is a SOAP-based Web service
• UDDI spec consists of programmer's API to publish/discover information
• SOAP requests/responses defined by XML Schema
• An "operator site" implements the UDDI specification
• Microsoft, IBM, and Ariba all have operator sites available today
• UDDI registry is a logically centralized, physically distributed service

424 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Universal Description, Discovery, and Integration (UDDI) defines how to interact


with a Web service information repository. UDDI is a quickly evolving standard
that is being jointly developed by Microsoft, IBM, and Ariba along with input
from other interested parties. The UDDI specification consists of a
programmer's API along with a XML Schema definition of supporting data
structures/messages. An "operator site" implements the UDDI specification and
allows users to 1) publish their own Web service information for increased
exposure, and 2) query the site for other's Web service information. Ironically,
UDDI is itself a Web service--all publish/inquiry operations are defined in terms
of SOAP.
You can think of UDDI as a cloud of Web service registries that share the
same publish/inquiry interfaces. The UDDI registry is a logically centralized,
physically distributed service with multiple root nodes that replicate data with
each other. So a business can register once with a single node of the business
registry service and publish everywhere. There is an operational registry
available today--Microsoft, IBM, and Ariba all have operator sites up and
running at the following URLs respectively:
http://uddi.microsoft.com/inquire, http://www-
3.ibm.com/services/uddi/inquiryapi,
http://uddi.ariba.com/UDDIProcessor.aw/ad/process. It remains to
be seen how many other organizations that use UDDI for publishing choose to
implement their own UDDI servers as opposed to leveraging one already in
place. Implementing a UDDI operator site is just like implementing any other
Web service. One must implement each of the operations defined by the UDDI
Programmer's API specification and format all response messages in accordance
with the UDDI datatypes schema.

Copyright © 2001, DevelopMentor Inc. 425


Module 11: XML-based Web Services

What is stored in UDDI registry?


UDDI registry consists of four main types of information

• Business information consists of name, contact info, services, etc.


• Service information provides business/technical descriptions of service
• Binding template defines how to connect to and communicate with service
• tModel provides a technical fingerprint for interfaces/behavior (or anything
else)

426 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

UDDI registries contain information about businesses, services, and service


bindings as well as additional metadata for categorization purposes. The way
UDDI organizes this information is conceptually similar to the "white pages",
"yellow pages", and "green pages". The white pages include business name,
address, and contact information. The yellow pages include industrial
categorizations based on standard taxonomies. And the green pages include the
technical specifications and references (see figure 11.26). UDDI registries
support several different types of lookups tailored for different user groups.

Name Retail URL


Address Health WSDL
Contact Finance tModel
.... ... ...

Figure 11.26: UDDI Pages

A UDDI registry contains four main types of information: businesses, services,


binding templates, and tModels. Each business in the registry exposes basic
information like name, address, and contact info as well as technical
information related to its services. Each of the services consists of
technical/business descriptions and categorizations. Each service also exposes
binding template information that describes how to connect to and
communicate with the given service (see figure 11.27).

business

tModel
service

binding

Figure 11.27: UDDI Information Items

The information provided by services and their binding templates isn't always
sufficient to determine compatibility. Simply knowing where to connect and
how to communicate is just the first step, one also needs to know the interface
contract and its associated behavior. A tModel is essentially a technical
fingerprint used to identify such things. tModels are used as binding template
metadata to help users determine if they're compatible with a given service
based on interface, behavior, or some other concept. tModels are just opaque

Copyright © 2001, DevelopMentor Inc. 427


Module 11: XML-based Web Services

identifiers that are registered with the UDDI site for more precise
identification. For instance, a tModel could refer to a WSDL document.

428 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Programming UDDI
UDDI Programmer's API divided into two groups of operations: inquiry and
publishing

• Inquiry API retrieves information from registry


• Inquiry API doesn't require authentication
• Publishing API inserts/updates information in[to] registry
• Publishing API does require authentication and encryption

430 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

The UDDI Programmer's API is divided into two groups of operations: inquiry and
publishing. The inquiry API provides operations for retrieving information from
the registry while the publishing API provides operations for publishing
information into the registry.
Figure 11.28 describes the UDDI inquiry operations. The APIs are SOAP-based
and have the format shown in 11.29. N.B. the SOAPAction header must be set
to "" for all requests. Anyone can use the inquiry APIs without being
authenticated by the operator site. The find_XXXX operations allow users to
perform criteria-based queries for businesses, services, bindings, and tModels.
Figure 11.30 illustrates how to perform a business lookup by name ("IBM
Corporation" in this case). The result of the find_business operation is a list
of businessInfo elements that contain information about its services (see
figure 11.31).
Name Description
find_business Locates information about one or more businesses.
find_service Locates services within a registered businessEntity.
find_binding Locates bindings within a registered businessService.
find_tModel Locates one or more tModel information structures.
get_businessDetail Gets businessEntity information for one or more businesses.
get_businessDetailExt Gets extended businessEntity information.
get_serviceDetail Gets full details for a set of registered businessServices.
get_bindingDetail Gets bindingTemplate information for making service requests.
get_tModelDetail Gets details for a set of registered tModels.

Figure 11.28: UDDI Inquiry API

<?xml version='1.0' encoding='utf-8'?>


<s:Envelope
xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>
<s:Body>
UDDI method request/response
</s:Body>
</s:Envelope>
Figure 11.29: UDDI SOAP request/response format

<find_business generic="1.0" xmlns="urn:uddi-org:api">


<name>IBM Corporation</name>
</find_business>
Figure 11.30: UDDI Find Business Example

Copyright © 2001, DevelopMentor Inc. 431


Module 11: XML-based Web Services

<businessList
generic="1.0" operator="Microsoft Corporation"
truncated="false" xmlns="urn:uddi-org:api">
<businessInfos>
<businessInfo
businessKey="D2033110-3AAF-11D5-80DC-002035229C64">
<name>IBM Corporation</name>
<description
xml:lang="en">At IBM, we strive to....
</description>
<serviceInfos>
<serviceInfo
businessKey="D2033110-3AAF-11D5-80DC-
002035229C64"
serviceKey="894B5100-3AAF-11D5-80DC-
002035229C64">
<name>Buy from IBM</name>
</serviceInfo>
<serviceInfo
businessKey="D2033110-3AAF-11D5-80DC-
002035229C64"
serviceKey="8937A1F0-3AAF-11D5-80DC-
002035229C64">
<name>IBM Software Support service</name>
</serviceInfo>
...
</serviceInfos>
</businessInfo>
</businessInfos>
</businessList>
Figure 11.31: UDDI Find Business Result

Alternatively, if one had the business key but didn't know the desired service
key, one could use find_service to search for a service by name as
illustrated in figure 11.32. The result of the find_service operation is a list
of serviceInfo elements containing the service details of those that
matched (see figure 11.33).
<find_service generic='1.0' xmlns='urn:uddi-org:api'
businessKey='D2033110-3AAF-11D5-80DC-002035229C64'>
<name>IBM Software Support service</name>
</find_service>
Figure 11.32: UDDI Find Service Example

432 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

<serviceList
generic="1.0" operator="Microsoft Corporation"
truncated="false" xmlns="urn:uddi-org:api">
<serviceInfos>
<serviceInfo
businessKey="D2033110-3AAF-11D5-80DC-002035229C64"
serviceKey="8937A1F0-3AAF-11D5-80DC-002035229C64">
<name>IBM Software Support service</name>
</serviceInfo>
</serviceInfos>
</serviceList>
Figure 11.33: UDDI Find Service Result

The get_XXXX operations allow users to retrieve the details of a particular


business, service, binding, or tModel. Once a service identifier has been
obtained (e.g., after a call to find_business or find_service), one can
call get_serviceDetails to retrieve full report of the specified service's
details as illustrated in figure 11.34. The result of this operation is a
businessService element that contains all the information about the
specified service (see figure 11.35).
<get_serviceDetail generic='1.0' xmlns='urn:uddi-org:api'>
<serviceKey>
8937A1F0-3AAF-11D5-80DC-002035229C64
</serviceKey>
</get_serviceDetail>
Figure 11.34: UDDI Get Service Detail Example

Copyright © 2001, DevelopMentor Inc. 433


Module 11: XML-based Web Services

<serviceDetail
generic="1.0" operator="Microsoft Corporation"
truncated="false" xmlns="urn:uddi-org:api">
<businessService
businessKey="D2033110-3AAF-11D5-80DC-002035229C64"
serviceKey="8937A1F0-3AAF-11D5-80DC-002035229C64">
<name>IBM Software Support service</name>
<description xml:lang="en">Some Service
used</description>
<bindingTemplates>
<bindingTemplate
bindingKey="6C19B6D0-3AAF-11D5-80DC-002035229C64"
serviceKey="8937A1F0-3AAF-11D5-80DC-002035229C64">
<description xml:lang="en">Some
description</description>
<accessPoint
URLType="http">http://server/endpoint</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo
tModelKey="uuid:68DE9E80-AD09-469D-8A37-
088422BFBC36" />
</tModelInstanceDetails>
</bindingTemplate>
</bindingTemplates>
...
</businessService>
</serviceDetail>
Figure 11.35: UDDI Get Service Detail Result

Figure 11.36 describes the UDDI publishing operations. The save_XXXX


operations allow users to register new information or update existing
information. Figure 11.37 illustrates how to save new business information to
the registry. The delete_XXXX operations allow users to remove information
from the registry. Since the publishing APIs mutate the operator site's registry,
user authentication and encryption is required before performing a publishing
operation. Users can authenticate themselves through get_authToken
operation specifying a user name and password. The site will then return an
authentication token that is used in all future publishing operations. Users can
then use the discard_authToken operation when they are done publishing
to invalidate the authentication token for future use. For examples of using the
publishing API, see the UDDI specification and related whitepapers.

434 Copyright © 2001, DevelopMentor Inc.


Module 11: XML-based Web Services

Name Description
get_authToken Requests an authentication token from an operator site.
get_registeredInfo Requests information currently managed by user.
save_business Registers/updates a businessEntity.
save_service Registers/updates a businessService.
save_binding Registers/updates a bindingTemplate.
save_tModel Registers/updates a tModel.
delete_business Deletes a businessEntity from registry.
delete_service Deletes a businessService from registry.
delete_binding Deletes a bindingTemplate from registry.
delete_tModel Deletes a tModel from registry.
discard_authToken Discards an existing authentication token.

Figure 11.36: UDDI Publishing API

<save_business generic="1.0" xmlns="urn:uddi-org:api">


<!-- retrieved from get_authToken API -->
<authinfo>
fd3c7a44-118f-413a-a2e3-473a35379993
</authinfo>
<businessEntity
businessKey="ee3be846-d828-4a38-a5e4-3c33f931d122">
<name>Developmentor</name>
<description>
Provides a services to the developer by...
</description>
<businessServices>
<!-- service descriptions go here -->
</businessServices>
</businessEntity>
</save_business>
Figure 11.37: UDDI Save Business Example

Copyright © 2001, DevelopMentor Inc. 435


Module 11: XML-based Web Services

Summary
• A "Web Service" is an application designed for software consumption
• The XML Schema language describes both the intrinsic type system for XML
and user-defined types
• XML + HTTP (or any other transport) = XML messaging
• SOAP defines a standard serialization/framing format for messages
• RPC-style applications can be constructed by combining two messages to
form an operation
• WSDL allows a collection of operations to be grouped together to form a
typed endpoint
• UDDI is an industry movement towards a distributed repository for Web
service publication/discovery

436 Copyright © 2001, DevelopMentor Inc.


Module 12

Resource Loaders

Copyright © 2001, DevelopMentor Inc. 437


After completing this module, you should be able to:
 Understand implicit class loading
 Manage class loader delegations
 Know when to use custom loaders
 Know when to use the context loader

438 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

Resource Loaders
Java manages resource loading via its class loader
architecture. Understanding class loaders is
essential to reliably assemble complex applications.

Copyright © 2001, DevelopMentor Inc. 439


Module 12: Resource Loaders

Resource Loader Architecture


The Java resource loader architecture is

• Safe
• Dynamic
• Namespace-aware
• Version-aware
• Network-aware
• Usable
• Extensible

440 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

Modern applications are far from monolithic. Rather, they are assembled at
runtime by combining a large number of different components. These
components may be developed by different vendors, located in different
repositories, and available in multiple versions. Assembling applications at
runtime is a complex process that must be managed carefully.
The Java Platform provides class loaders as its basic building block for
assembling applications. Despite their name, class loaders can be used to a
wide variety of application resources. The class loader architecture is safe,
dynamic, extensible, namespace-aware, version-aware, network-aware, and
usable.
The class loader architecture is safe. When a loader requests a Java class,
the virtual machine verifies that the class is a valid Java class, and that it
meets the contractual requirements of its caller.
Class loaders are dynamic. You can create your own class loader instances at
runtime to load code from arbitrary locations.
The class loader architecture is namespace-aware. Class loaders combine
into delegations that define a namespace
Class loaders are version-aware. You can use jar sealing and package
metadata to guarantee that you locate the correct version of a resource.
Class loaders are network-aware. The URLClassLoader provides support
for the http protocol, and pluggable protocol handlers enable custom
protocols.
Class loaders are usable. In addition to the explicit class loader APIs, Java
defines implicit class loading to shield application developers from deployment
complexities.
The class loader architecture is extensible. You can define your own custom
class loaders that execute customized strategies to locate or create resources.

Copyright © 2001, DevelopMentor Inc. 441


Module 12: Resource Loaders

Internal Safety
Class verification guarantees internal consistency

• Strongly-typed bytecodes
• Predictable use of local variable slots
• Predictable use of stack slots

442 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

The verification process guarantees that classes cannot harm the virtual
machine. Java bytecodes are strongly-typed, so illegal casts cannot be used to
gain illegal pointer access to Java objects or VM internals. Legal bytecode must
make predictable use of local variable slots; stores and loads must be type
safe. The same is true of stack slots; all pushes and pops must match.
Figure 12.1 shows a simple Java method and its bytecode, decompiled using
the javap tool. Notice that all of the instructions are strongly typed by the "f"
or "i" prefixes.
public int add(int one, float two) {
return one + (int) two;
}

/* Decompiled with javap -c


Method int add(int, float)
0 iload_1
1 fload_2
2 f2i
3 iadd
4 ireturn
*/
Figure 12.1: Bytecodes are strongly-typed

Copyright © 2001, DevelopMentor Inc. 443


Module 12: Resource Loaders

Referential Safety
Loader guarantees binary compatibility between classes

• Classes refer to other classes, fields, and methods


• References become indices in binary class's constant pool
• Constant pool preserves fully qualified names
• Language protection modifiers enforced at runtime

444 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

In live systems, classes may be modified over time, and fields and methods may
be added, deleted, or changed. The VM guarantees that any compile-time
references between classes are still valid at runtime. The binary class format
contains complete type information for a class. If class A references class B, a
fully qualified reference is stored in class A's constant pool. When the
reference needs to be resolved at runtime, the reference in class A's constant
pool is compared with class B's type information. If the references do no
match, the runtime throws a LinkageError.
The binary class format also preserves the protection level of fields and
methods: public, private, protected, or default. The means that the protection
rules can be enforced at runtime. (In some languages, the protection rules are
a compile-time phenomenon that leaves no trace in the compiled output.)

Copyright © 2001, DevelopMentor Inc. 445


Module 12: Resource Loaders

Dynamic Class Loading


New class loader instances change how classes are loaded at runtime

• CLASSPATH is the default search path


• Create an URLClassLoader for any arbitrary URL

446 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

By default, classes are loaded from the list of directories and jars contained in
the CLASSPATH. However, this behavior is easily overridden. Simply instantiate
a URLClassLoader pointed to some different location, and call the explicit
loadClass method. Figure 12.2 shows how.
URL u = new URL("http://www.develop.com/classes/");
URLClassLoader ldr = new URLClassLoader(new URL[]{u});
Class cls = ldr.loadClass("Foo");
Object inst = cls.newInstance();
Figure 12.2: Explicit class loading

Copyright © 2001, DevelopMentor Inc. 447


Module 12: Resource Loaders

Class Loaders as Namespaces


Each class loader delegation defines a namespace

• All class loaders are organized in a tree


• Delegation is set of loader and all ancestors
• Within a delegation class names unique
• Different delegation, different namespace
• Permits sharing, prevents collisions

448 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

The class loader architecture allows multiple classes with the same name to
coexist in a single virtual machine. To support this behavior, all class loaders
are organized into a tree. You can access a class loader's parent in the tree by
calling getParent. At the top of the tree getParent returns null.
The set of a loader and all of its ancestors is called a delegation. Within a
delegation, a class name is unique. Once a particular class is loaded,
subsequent calls to loadClass will return the already loaded class. Figure
12.3 shows a sample class loader tree. The dotted line encircles the delegation
for AppCL_4.

BCL

Delegation of
AppCL_4
ECL

SCL

AppCL_1 AppCL_2

AppCL_3 AppCL_4

Figure 12.3: Class Loader Delegation

Copyright © 2001, DevelopMentor Inc. 449


Module 12: Resource Loaders

Whenever a class loader is asked to load a class, it first delegates to its parent
class. This causes the entire delegation to be consulted, and gives priority to
loaders higher in the tree. In Figure 12.3, imagine that AppCL_4 is asked to
load java.lang.String. AppCL_4 delegates to AppCL_2, which delegates to
SCL, then to ECL, and finally to BCL. BCL stands for "Bootstrap Class Loader"
which is always the top loader. The BCL loads core system classes, and will be
able to load the String class.
The delegation model allows fine-grained control over how classes are
shared within a virtual machine. All delegations will share the same version of
java.lang.String, because it is loaded by the most senior loader. Classes
loaded further down the delegation may not be shared. For example, if
AppCL_4 loads a class Foo, then AppCL_3 will be able to load a different
version of Foo.
Loading multiple classes with the same name has two benefits. First, it
prevents name collisions if two organizations accidentally use the same class
name. Second, it allows a single organization to deploy multiple versions of a
class simultaneously.
The three class loaders at the top of Figure 12.3 are standard for all Java 2
applications. The Bootstrap Class Loader (BCL) loads system classes. The
Extensions Class Loader (ECL) loads extensions, i.e. jar files places in
JRE/lib/ext. The System Class Loader (SCL) loads resources from the classpath.
Class loaders after these first three are application-specific.

450 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

Version Support
URLClassLoader supports sealing and package metadata

• Seal packages to prevent version hybrids


• Set package metadata
• Deploy jars not classes
• Version support helpful but incomplete

452 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

URLClassLoader and jar files combine to provide limited support to cope


with multiple versions of a class. When you create a jar file, you can use the
manifest to specify that some or all the contained packages are sealed. When a
package is sealed, all classes in that package must come from the same jar file.
This prevents the accidental loading of version hybrids, where parts of
different versions of the same API are loaded from different jar files.
JAR files can also specify six pieces of version metadata for a package, as
shown in Figure 12.4. The content of these strings is arbitrary, and is not used
in any way by the virtual machine. However, you can access the strings at
runtime using the java.lang.Package APIs. You could, for example, check
that a version string is the one that you expected or throw an exception.
Manifest-Version: 1.0
Sealed: true
Implementation-Title: WidgetImpl
Implementation-Version: 1.4
Implementation-Vendor: WidgetMentor
Specification-Title: Widget
Specification-Version: 1.0.0
Specification-Vendor: Widget3C
Figure 12.4: JAR Manifest

Sealing and package metadata represent a small attack on a large problem.


Sealing can guarantee that all package classes come from one jar, but if there
is a deployment problem your only option is to fail fast. The Package class
reports version information, but only after you have loaded a class, which may
well be too late.

Copyright © 2001, DevelopMentor Inc. 453


Module 12: Resource Loaders

Loading Over a Network


URLClassLoader provides flexible, safe network loading

• HTTP support built-in


• Java security prevents attacks
• URL allows pluggable custom protocols

454 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

URLClassLoader can load classes over the network just as easily as from the
local file system. This can greatly simplify deployment. If a group of machines
can all load code from a shared server, then only the server needs to be
updated (see Figure 12.5).

Code Server

http://codeserver/classes

Figure 12.5: Loading Classes from a Shared Server

Java applications can install a security manager to protect themselves from


rogue code downloaded over the network. Administrators use policy files to
control access to the file system, network, native code, and other sensitive
resources.
Java's URL class permits pluggable protocol definitions. To create your own
protocol, subclass URLStreamHandler and set the
java.protocol.handler.pkgs property. Custom URLs can be used directly
or in conjunction with URLClassLoader.

Copyright © 2001, DevelopMentor Inc. 455


Module 12: Resource Loaders

Using and Extending Loaders


Most class loading is implicit, but there are some
idioms that you should follow to work well in
container environments. You can create custom
loaders to take complete control.

Copyright © 2001, DevelopMentor Inc. 457


Module 12: Resource Loaders

Ease of Use
Most of the details of class loading are hidden

• References trigger implicit loading


• VM calls getClassLoader
• VM calls loadClass
• Loading co-located resources is trivial

458 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

It is important to use class loaders explicitly when you want to modify how
code is brought into the virtual machine. Most of the time, such decisions only
need to be made a small number of times relative to the total number of
classes. Also, most Java code is not littered with calls to loadClass. How do
all the other classes get loaded?
Most classes are loaded via implicit loading. Whenever one Java class refers
to another, the virtual machine automatically loads the class. The VM calls
getClassLoader on the current class, and then calls loadClass to load the
referenced class. Figure 12.6 demonstrates what happens behind the scenes.
Widget w = new Widget();

//pseudocode, behind the scenes of "new Widget()":


Class cls =
getClass().getClassLoader().loadClass("Widget");
Object o = cls.newInstance();
return (Widget) o;
Figure 12.6: Behind the scenes of implicit loading

Thanks to implicit class loading, there is no need to explicitly call loadClass


for any classes that are visible to the current delegation. Simply reference
them and the VM will do the rest. The only time you need to call loadClass
explicitly is to bootstrap the process for a particular loader.

Copyright © 2001, DevelopMentor Inc. 459


Module 12: Resource Loaders

Using an Explicitly Loaded Class


To use an explicitly loaded class:

• Explicitly load a class


• Implicitly load a base interface
• Store instances in base type references
• You must separate interface from implementation

460 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

You can explicitly load classes as often as you like. But, where will you store
references to instances you create? In order to store a reference, you must
declare a variable or field. Assigning to a field or variable will trigger implicit
class loading. So, instances of explicitly-loaded classes must be stored via
references to implicitly loaded classes.
This idiom commonly appears when loading and using classes further down
the delegation tree. Figure 12.7 shows one example. The interface Widget is
loaded implicitly and must be visible to Client's delegation. The
implementation class WidgetImpl is loaded explicitly by some lower loader.
Later, the client can choose to load a different version of WidgetImpl simply by
instantiating another loader.
class Client {
public void useWidgets() {
ClassLoader l = createSomeClassLoader();
Widget w = (Widget)
l.loadClass("WidgetImpl").newInstance();
w.run();
w.stop();
ClassLoader other = createSomeOtherLoader();
w = (Widget)
other.loadClass("WidgetImpl").newInstance();
w.run();
w.stop();
}
}
Figure 12.7: Explicitly loading an implementation class

Copyright © 2001, DevelopMentor Inc. 461


Module 12: Resource Loaders

Using the Context Loader


The context loader adds another level of control

• Explicit loading controlled by code


• Implicit loading controlled by deployment
• Deployers need more flexibility
• Containers set context loader
• Developers write context-aware code

462 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

There are several situations when the naive application of implicit and explicit
loading is inadequate. Implicit loading cedes control to the deployer of an
application. Classes will be loaded based on the delegation tree. Deployers can
change which classes get loaded by installing class and JAR files in different
locations. However, the rigid delegation rules are too inflexible for some
situations. If there are complex dependencies between several classes, then
they may all have to be placed in the same location.
Explicit class loading would solve this problem, but can lead to cluttered,
confusing APIs. If you are not sure which methods might need to load new
classes, you could end up adding a ClassLoader parameter to every method
signature, just in case.
The context class loader is a compromise between these two extremes. The
context loader is simply a well-known slot in thread-local storage. The code
that launches a process, such as a servlet engine, sets an appropriate context
class loader. Then, the context loader is available to any code that needs a
loader, without requiring that clients pass ClassLoader arguments to every
method. Application code must explicitly request the context loader to take
advantage of its capabilities.
The context loader is often used to implement factory methods. Figure 12.8
shows how to set the context loader, and then use it from a Widget factory.
The WidgetFactory needs to know where to look for WidgetImpl. Rather
than checking an explicit loader argument, the factory assumes that the
process owner has already initialized the context loader to point to the
appropriate loader. Notice that the client code is very simple and entirely
hides class loading details.
//container startup code
Thread.currentThread().setContextClassLoader(someLdr);

//factory code
public Widget getWidget() {
Loader ldr =
Thread.currentThread().getContextClassLoader();
Class cls = Class.forName("WidgetImpl", true,
ldr).newInstance();
return (Widget) cls.newInstance();
}

//client code
Widget w = WidgetFactory.getWidget();
w.run();
Figure 12.8: Explicitly loading an implementation class

Copyright © 2001, DevelopMentor Inc. 463


Module 12: Resource Loaders

If you are implementing factory methods, you should typically prefer the
context loader to implicit loading. Factory methods that do not use the context
loader are the source of many arcane problems in server applications.

464 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

Extending Class Loading


Use custom class loaders to change how code is loaded

• Instrument existing classes


• Access custom attributes
• Generate classes on-the-fly

466 Copyright © 2001, DevelopMentor Inc.


Module 12: Resource Loaders

Most class loader needs can be met using either URLClassLoader or the class
loaders that are provided by a J2EE container environment. However, it is
simple to write a custom class loader. All a custom class loader needs to do is
implement the findClass method, which takes a string name, locates the
binary class bytes, and calls the native method defineClass as shown in
Figure 12.9

Java Virtual Machine

1. loadClass
2. findClass
Class Class
3. defineClass Loader Repository

Figure 12.9: Class Loaders Call Back into the VM

Because they access the class bytes before passing them into the virtual
machine, custom class loaders can modify class binaries as they are loaded.
This feature is used to inject instrumentation for debugging or performance
analysis.
Custom class loaders can also access custom attributes, which are part of
the binary class format. The VM spec allows class files to carry custom
attributes, but these attributes are not made visible anywhere in the Java API,
so you must use a custom class loader to reach them. One obvious use for
custom attributes would be to embed stricter versioning rules.
Custom class loaders could also generate classes from scratch. Although not
a trivial undertaking, such a custom loader might provide great performance
speedups by converting some non-Java instructions into a "compiled" class.

Copyright © 2001, DevelopMentor Inc. 467


Module 12: Resource Loaders

Summary
• Applications must be assembled at runtime
• Class loaders manage app assembly
• Implicit loading is easy to use
• Explicit loading gives fine control
• The context loader leaves the process owner in control

468 Copyright © 2001, DevelopMentor Inc.


Module 13

Type Information

Copyright © 2001, DevelopMentor Inc. 469


After completing this module, you should be able to:
 Use Reflection to access type information
 Build generic services
 Build dynamic proxies
 Understand how containers use type information

470 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Type Information
Java type information is accessible at runtime via
Reflection, and is used to develop generic services.

Copyright © 2001, DevelopMentor Inc. 471


Module 13: Type Information

Type Information
Languages and platforms are type systems

• What is your name?


• What do you consist of?
• What can you do?

472 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Programming languages and platforms are, at their core, type systems. The
Java language specifies that classes have names, that they consist of fields,
and that their behaviors are accessible through methods. Fields, in turn, are
names and types. Methods are names plus parameter lists, which are arrays of
types.
Type systems are used to validate contractual relationships between
components of a system. When you compile a Java program, the compiler will
balk if you attempt to reference a type, field, or method that does not exist.
This compile-time enforcement prevents programming errors by encoding
assumptions about the model.
Modern language platforms embed type information into their binary formats
as well. A Java binary class contains exactly the same type information as a
source file. Given either format, it is possible to generate the other.

Copyright © 2001, DevelopMentor Inc. 473


Module 13: Type Information

Runtime Type Information


Java exposes RTTI through a sensible class library

• java.lang.Class
• java.lang.reflect.Method
• java.lang.reflect.Field
• java.lang.reflect.Constructor

474 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

You do not have to crack the binary class format to extract type information at
runtime. Java Reflection provides a programmatic API to all the standard type
information through the Class, Method, Field, and Constructor classes.
Figure 13.1 shows the reflection object model.

getField
Object Field

getClass Array

getMethod
Class Method

Package

Constructor
getConstructor

Figure 13.1: Reflection Object Model

Class represents a Java class. You can obtain a class object by calling
getClass on any instance, or by using the compiler shortcut
ClassName.class. Class provides access to fields, methods, and
constructors through the APIs showing in Figure 13.2.
public Field[] getFields();
public Field[] getDeclaredFields();
public Field getField(String name);
public Field getDeclaredField(String name);

public Method[] getMethods();


public Method[] getDeclaredMethods();
public Method getMethod(String name, Class[] argtypes);
public Method getDeclaredMethod(String name, Class[]
argtypes);

public Constructor[] getConstructors();


public Constructor[] getDeclaredConstructors();
public Constructor getConstructor(Class[] argtypes);
public Constructor getDeclaredConstructor(Class[]
argtypes);
Figure 13.2: Accessing Fields, Methods, and Constructors

Copyright © 2001, DevelopMentor Inc. 475


Module 13: Type Information

Accessors named getXXX return public members only, and recurse to all base
classes/interfaces. Accessors named getDeclaredXXX return all members
regardless of protection modifier, but do not recurse to base classes.
Method, Field, and Constructor provide access to their constituent
parts through the methods shown in Figure 13.3.
//shared by all
public int getModifiers();
public Class getDeclaringClass();

//Field
public String getName();
public Class getTypes();

//Method
public Class getReturnType();

//Method and Constructor


public Class[] getParameterTypes();
public Class[] getExceptionTypes();
Figure 13.3: Interrogating Fields, Methods, and Constructors

476 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Reflective Modification
Can use reflection package to dynamically modify objects

• Load classes
• Set fields
• Invoke methods
• Call constructors
• Ignore protection modifiers

478 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Reflection can do more than just interrogate the type system; it can
dynamically modify Java objects at runtime. You can load classes, get and set
fields, invoke methods, and call constructors dynamically at runtime, without
needing any compile-time knowledge of the classes involved. Reflective access
is a potent source of code reuse because it does not impose any particular
requirements on the classes to be accessed.
One simple use of reflective access is the factory design pattern. By loading
classes dynamically, it is possible to separate interface from implementation,
and select implementation classes at runtime. Figure 13.4 shows this
technique. Notice the large number of checked exceptions the method throws.
This is a consequence of using reflection: since type relationships are not
checked at compile time, defects will trigger exceptions at runtime.
public class AirplaneFactory
throws ClassNotFoundException, InstantiationException,
IllegalAccessException
{
public Airplane newAirplane(String implClass) {
Class cls = Class.forName(implClass);
Object o = cls.newInstance();
return (Airplane) o;
}
}
Figure 13.4: Implementing a Factory

Reflection can even be used to bypass language protection modifiers. This


ability is critical because reflection is used to build persistence services that
need access to private data members. By default, reflection enforces language
protection modifiers. Trusted code such as a persistence service can deactivate
protection by calling setAccessible(true). Java platform security can be
used to distinguish which services are trusted to make this decision. Figure 13.5
shows part of a simple XML data binding that calls setAccessible to access
private fields.

Copyright © 2001, DevelopMentor Inc. 479


Module 13: Type Information

Field[] flds = cls.getDeclaredFields();


int count = flds.length;
for (int n=0; n < count; n++) {
Field f = flds[n];
f.setAccessible(true);
Object subObj = f.get(obj);
if (!Modifier.isStatic(f.getModifiers())) {
if (f.getType().isPrimitive()) {
emitPrimitiveXML(f.getName(), subObj);
} else {
emitClassXML(subObj, pos);
}
}
}
Figure 13.5: Using setAccessible

480 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Dynamic Proxies
DPs are classes generated from type information

• Implement a set of interfaces


• Forward to an InvocationHandler
• Implement AOP dynamically

482 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Type information can also be used to generate new classes at runtime. The
Java SDK version 1.3 provides one example of this, the
java.lang.reflect.Proxy class for generating dynamic proxies.
A dynamic proxy is generated at runtime to implement a set of interfaces.
All proxy methods are forwarded to a single generic InvocationHandler.
Usually, a proxy is used to perform some pre- and post- processing of a method
call, as shown in 13.6. Figure 13.7 shows a factory that wrap auditing
functionality around an existing object.

deposit Account
Client Account
Auditor
invoke
withdraw

Auditing
deposit Dyn.
Client Invocation Account
Proxy
invoke Handler invoke
withdraw

Figure 13.6: Intercepting Method Calls with a Proxy

Copyright © 2001, DevelopMentor Inc. 483


Module 13: Type Information

class Auditor implements InvocationHandler {


private Object delegate;
public Auditor(Object o) {
delegate = o;
}
public Object invoke(Object proxy, Method meth, Object[]
args)
throws Throwable {
System.out.println("Calling " + meth.getName());
try {
return meth.invoke(delegate, args);
}
catch (InvocationTargetException ite) {
throw ite.getTargetException();
}
}
public static Object getAuditor(Object o, Interface[]
itfs) {
return
Proxy.newProxyInstance(o.getClass().getClassLoader(),
itfs, new Auditor(o));
}
}
Figure 13.7: Creating an Auditor Proxy

Proxies make it possible to view method calls as request and response


messages, which can then be intercepted to implement cross-cutting
functionality. Cross-cutting functionality is functionality that does not
"separate out" in an OO design. Cross-cutters end up sprinkled across the
system, making them difficult to modify or maintain. Some examples of cross-
cutters are security, auditing, transaction management, and parameter
validation. With proxies you can factor these concerns into one location in the
program.
Proxies are a simple example of Aspect-Oriented Programming, which
separates cross-cutters into source artifacts called aspects. AspectJ is another
example; it defines an aspect syntax and weaves aspect code into classes
during development.

484 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Type-driven services in J2EE


J2EE == containers plus type-driven services

• Object / relational mapping


• Serialization
• Remoting
• Interop, particularly XML
• EJB: Aspects Simplified

486 Copyright © 2001, DevelopMentor Inc.


Module 13: Type Information

Understanding type-driven services is critical to understanding how to use and


extend J2EE-based application designs. J2EE is simply containers plus type
services. The containers provide a process environment to host your Java code.
Containers provide process configuration, thread pooling, database drivers,
socket management, and other low-level services so that you can concentrate
on the problem domain.
Containers also provide services that are tuned specifically to your code?
How can they do that, given that they cannot know what your code will look
like? They use type information to generate services based on code that you
deploy.
Containers use Java serialization, and other similar mechanisms, to transport
objects from one location to another. Containers can use serialization to move
objects from one virtual machine to another, which helps with fault tolerance,
load balancing, and system updates.
Containers use type information to generate remoting code so that objects
can be accessed from other machines. Obviously, remoting is central to
enterprise applications, where resources live in different physical locations.
Type information is central to interoperating with other organizations (and
their disparate software platforms). This piece of the puzzle is not fully spec'ed
out in J2EE today, but is becoming increasingly important as XML becomes the
lingua franca of B2B interop. Java is a dominant language for XML in part
because Java type information makes it easy to generate Java/XML mappings.
Last and least, understanding type information (particularly dynamic
proxies) makes it easy to understand Enterprise Java Beans (EJB). Put simply,
EJB is a least-common-denominator approach to aspect-oriented programming.
EJB restricts AOP to a few aspects (transactions, O/R mapping, and security)
and provides a simplistic model to ease vendor compliance.

Copyright © 2001, DevelopMentor Inc. 487


Module 13: Type Information

Summary
• Java type information available at runtime
• Reflection enables generic services
• Proxies implement cross-cutting concerns
• Containers build type-driven services
• Type information facilitates XML

488 Copyright © 2001, DevelopMentor Inc.


Module 14

EJB Entities

Copyright © 2001, DevelopMentor Inc. 489


Object-relational mapping

After completing this module, you should be able to:


 understand the purpose and role of an entity
 learn how the container manages entity persistence
 discover why an entity might manage its own persistence
 understand the entity concurrency model
 appreciate the dangers of naive use of entities

490 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Introduction to entities
Entities shield session beans from the details of
data access by making all persistent data, regardless
of its origin, appear as a local java object.
Essentially, the container caches persistent data in
the middle-tier in an attempt to make data access
faster, while providing the concurrency and
synchronization services necessary to keep the data
consistent.

Copyright © 2001, DevelopMentor Inc. 491


Module 14: EJB Entities

What is an entity?
Common OO view of persistent data, regardless of origin

• Often from an [R]DBMS


• Two persistence models
• Entities that represent shared, r-w data are transactional (CMT=Required)
• Two concurrency models
• Often viewed as a middle-tier database cache

492 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

An entity bean is an in-memory representation of a persistent entity held in


some data store, providing a common object-oriented view of the underlying
entity regardless of its origin or structure. Such persistent entities are often
stored in a database, for instance as a row in a table, although not necessarily.
The entity bean knows how to read its data from persistent store and write any
changes back again, but to the client of an entity bean the details of the data
storage and access mechanism are hidden. In fact, entity beans support two
persistence models. The first model is where the container implements the
code to map the entity bean fields to the underlying entity data based on
declarative mapping information. This is called container-managed persistence
(CMP) and often, although not necessarily, maps the entity bean to a database.
The usefulness of this technique is very much dependant on the richness and
flexibility of the container's mapping language. The second model is where the
entity bean implements all the code to map its fields to the underlying entity
data. This is called bean-managed persistence (BMP) and allows the bean the
flexibility to map to any data store using any data access technique it chooses.
Figure 14.1 shows the two models.

Deployment
Descriptor
Managed field list
Mapping details
Used to build

r EJB Object
e
m CMP bean Persistence
o Layer
t SQL
e Bean fields Container writes
i/f data access code

r EJB Object
e
m BMP bean Persistence
o Layer SQL
t
e Bean fields Bean writes
i/f data access code
Legacy
Application

Figure 14.1: Entity persistence models

Copyright © 2001, DevelopMentor Inc. 493


Module 14: EJB Entities

An entity bean that represents shared, read-write data that is manipulated in a


concurrent environment must be accessed under a transaction in order to
ensure data consistency. In this case, an entity bean is always composed into a
transacted middle-tier operation as provided by a session EJB or a Servlet/JSP.
Such entities must behave correctly if they are composed into an existing
transaction (the norm) but must also remain self-consistent if used outside of a
transaction. For this reason entity beans cannot use bean-managed transactions
(they could not be composed into an existing transaction) and only the
"Required" attribute has the correct semantics if the entity uses container-
managed transactions. The EJB specification allows the container to share
entity bean instances in memory. In the case where it does, the container is
responsible for the transaction isolation and essentially ensures that access to
the bean is single-threaded. The EJB specification also allows different entity
bean instances in memory to access the same data (as might happen in a
cluster). In this case the beans can be accessed concurrently and the
underlying data store is responsible for transaction isolation. Figure 14.2
illustrates. Remember that external non-EJB applications might also be
manipulating an entity's underlying data.

Tx isolation
machine 1 provided
by database
r EJB Object
session e
m bean
ref 1 Other app
i/f

r EJB Object
session e
ref 2 m bean
i/f

session
ref 3 r EJB Object
e
m bean
Tx isolation
session i/f
provided
ref 4
by container
machine 2

Figure 14.2: Entity concurrency models

When used to access a remote data store, an entity bean represents a cache of
data in the middle tier. Data is swapped back and forth between the database
and middle tier on demand. How useful the cache is depends on how often the
cache needs to be synchronized with the data store and how optimized the
data transfer is.

494 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Entity bean basics


Entities are long lived

• Entity data outlives entity bean instance


• Entity data created manually or programmatically via home interface
• Entity data deleted manually or programmatically via home/remote
interface
• Entities identified and located by primary key using home interface
• Remote interface methods wrap underlying instance data
• Home interface defines instance-less methods (EJB 2)
• Exact details of bean implementation/deployment depend on bean
persistence model

496 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

An entity bean is like any other EJB--it has a remote interface, a home
interface, an implementation class and a deployment descriptor. The remote
interface is the client's view of the entity bean and provides selective access to
the underlying data of the bean via accessors and mutators--either a field at a
time or using bulk transfer. A typical example is shown in figure 14.3. The
home interface represents the client's ability to create or find an entity bean
and execute class-level (instance-less) methods on the entity bean. The bean
class implementation determines exactly how the entity bean maps to its data
and is responsible for interacting with the container during its lifetime. The
deployment descriptor contains information used by the container and/or the
entity bean to map the entity bean to its data. The entity bean class
implementation and the deployment descriptor details depend entirely on the
bean's persistence mechanism (bean-managed, EJB 1.1 container-managed or
EJB 2.0 container-managed).
import javax.ejb.*;
import java.rmi.*;

public interface CustomerEntity extends EJBObject


{
public int getID() throws RemoteException;
public String getName() throws RemoteException;
public void setName(String s) throws RemoteException;
...
}
Figure 14.3: Entity remote interface

An entity bean instance provides a temporary, in-memory view of some


underlying persistent data and can always be constructed to view the data
while it exists. So using some out-of-band technique, such as inserting or
deleting a row in a database table, is enough to create or destroy a potential
entity bean instance. Entities and their underlying data can also be created and
destroyed programmatically if desired. Figure 14.4 shows an example of a
home interface that contains a single create() method used by an EJB client
to create an entity. The parameters to any create() method represent the
initial field values for the entity's underlying data. Note that create()
methods are optional--if none are provided then the entity cannot be created
programmatically. Any number of create() methods with any number of
parameters may be supplied.

Copyright © 2001, DevelopMentor Inc. 497


Module 14: EJB Entities

import javax.ejb.*;
import java.rmi.*;

public interface CustomerEntityHome extends EJBHome


{
// Optional - If no create() then entity data must be
// created by other means
public CustomerEntity create(int id, String name,
int age)
throws CreateException, RemoteException;
...
}
Figure 14.4: Creating an entity via its home interface

An entity in a data store outlives any particular client that uses it. Once an
underlying entity has been created, by whatever means, it can be located using
its primary key. A primary key is some combination of fields whose values can
be used to uniquely identify a particular entity. For a customer entity the
primary key would be the customer ID field. Each entity bean class is
associated with a corresponding primary key class that represents the
underlying entity's primary key. The primary key class is associated with the
entity bean class by storing its details in the entity bean's deployment
descriptor. The primary key class is used by the EJB client to locate a reference
to a particular entity bean by calling the findByPrimaryKey() method in
the entity bean's home interface. This method is mandatory. Figure 14.5 shows
an example home interface. Optionally, other finders can be provided, often to
locate collections of entities.
import javax.ejb.*;
import java.rmi.*;
import java.util.*;

public interface CustomerEntityHome extends EJBHome


{
...
// Required
public CustomerEntity findByPrimaryKey(
CustomerEntityPK pk)
throws FinderException, RemoteException;
// Optional
// Can return java.util.Collection for Java2-only clients
public Enumeration findWhereAgeGreaterThan(int age)
throws FinderException, RemoteException;
...
}
Figure 14.5: Finding an entity via its home interface

498 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

The exact details of the primary key definition depends on the bean's
persistence mechanism (bean-managed or container-managed) but in essence
there are two main ways of defining a primary key. The first is a simple primary
key class that maps to a single underlying primary key field. This technique
allows a type such as a java.lang.Integer to be used as a primary key class
without having to wrap it up inside something more complex. The second is to
define a class whose data members represent an arbitrarily complex underlying
compound primary key. Figure 14.6 shows what this might look like. The
primary key can be obtained from an entity bean reference using
EJBObject.getPrimaryKey() and can be persistently stored if required as
the primary key class is always serializable.
public class CustomerEntityPK implements java.io.Serializable {
public int id;
public CustomerEntityPK(int id) {this.id=id;};
// Required (implement them sensibly!)
public boolean equals(Object obj) {
return (obj!=null && obj instanceof CustomerEntityPK &&
((CustomerEntityPK)obj).id==id;
}
public int hashCode() {return id;}
}

CREATE TABLE CUSTOMER( CID INTEGER PRIMARY KEY,


CNAME VARCHAR(64),
CADDRESS VARCHAR(128),
CAGE INTEGER)

Figure 14.6: Primary key class

The default implementation of the equals() method (in


java.lang.Object) will return true only if two object references are equal
(i.e. they refer to the same object). Similarly the default implementation of
the hashCode() method (in java.lang.Object) is typically implemented by
converting the internal address of the object into an integer. To ensure correct
behaviour when the EJB container is comparing primary keys, we must ensure
that two different references to two different primary keys are considered
equal. For this reason EJB 1.1 and later forces us to override equals() and
hashCode() when defining our own primary key class. Given that it is
impossible to predict how often the container will need to compare instances
of the primary key class and given that the primary key class can be arbitrarily
complex, then care should be taken to make sure these methods are
implemented as efficiently as possible.

Copyright © 2001, DevelopMentor Inc. 499


Module 14: EJB Entities

With EJB 2 it is also possible to use an entity's home interface to expose


instance-less methods. These are for exposing bean logic that is not specific to
any entity instance, and their names must not start with "create", "find" or
"remove". Figure 14.7 illustrates.
import javax.ejb.*;
import java.rmi.*;

public interface CustomerEntityHome extends EJBHome


{
...
// EJB 2.0 only
public int getAverageAge() throws RemoteException;
public int numAccounts(int bal) throws RemoteException;
...
}
Figure 14.7: Instance-less methods in the home interface

To delete an entity and its underlying data programmatically simply call one of
the remove() methods in the home or remote interface. Figure 14.8 shows
how the client creates, finds, uses, and deletes an entity.
CustomerHome ch=(CustomerHome)doLookup("CustomerHome");
Customer c1=ch.create(3, "Kevin Jones", 39);
System.println("Customer id is " + c1.getID());
CustomerEntityPK pk = new CustomerEntityPK(); pk.id=5;
Customer c2=ch.findByPrimaryKey(pk);
System.println("Customer name is " + c2.getName());

// EJB 2.0 only


System.println("Average customer age is " +
ch.getAverageAge());
int bal = 1000;
System.println(ch.numAccounts(bal) +
" customer accounts with balance > " +
bal);

pk.id=10;
ch.remove(pk);
c2.remove();
Figure 14.8: Creating, finding, destroying an entity

500 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Entity bean lifecycle


Container in charge of entity bean lifetime

• Container pools beans without identity


• Container gives bean identity when required by client
• One bean instance can represent many identities during lifetime
• Bean with identity must synchronize with underlying data store
• Container notifies bean of important events during its lifetime
• Bean class implements javax.ejb.EntityBean,
ejbCreate()s/ejbPostCreate()s
• Bean class may implement other call-back methods depending on
persistence model

502 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

The EJB interception model places an interceptor between the client and an
instance of a bean class. The nature of an entity bean class allows the
container to take maximum advantage of this disassociation when managing
the lifetime of an entity bean instance.
An entity bean class represents a view on an entity in a persistent data store
and the rules for accessing and manipulating that entity. It knows the type of
the entity but it doesn't dictate a specific entity--it relies on the container to
tell it which specific underlying entity it represents at any given time. To
amortise the cost of continually creating and destroying instances of a bean
class as they are needed, a single bean instance can be reused by the container
over time to represent different identities on behalf of different clients. For
instance, during its lifetime an instance of a customer entity bean class always
represents a customer, but over time it may represent customer 4 ("Fred
Bloggs"), customer 324 ("Jane Smith"), customer 45 ("Kevin Jones") and so on,
as needed. While a bean instance has no identity (is not needed to represent a
particular entity to a set of clients) it languishes in the pool with other
identity-less bean instances of the same class. When the container needs a
bean instance to service a client it takes one (any one) from the pool and gives
it identity. When the bean instance is no longer required by any client, its
identity is removed and it is returned to the pool. Pooling is not mandated by
the EJB specifications but all containers do it.
The client's expectation is that it has a reference to a particular entity bean.
In reality the client has a reference to an interceptor that may not always be
attached to an instance of a bean class. This is OK as each interceptor knows
its identity--the container associates it with a particular instance of the bean's
primary key class. The bean is able to provide an identity-less bean with
identity by attaching it to an interceptor. The interceptor's primary key
provides the bean with its identity and allows it to map to the correct data.
Figure 14.9 illustrates.

Copyright © 2001, DevelopMentor Inc. 503


Module 14: EJB Entities

EJB Object
r
e Primary key
session m
ref 1 i/f

session EJB Object


r
e Primary key
ref 2
m
Bean
i/f (with identity)
session Pool
ref 3 EJB Object Bean
r
e Primary key Bean
(no identity)
m Bean
(no identity)
session Bean (noBean
identity)
i/f (with identity) (no identity)
ref 4

Figure 14.9: How the container manages entity bean instances and their
identity

All of this means that the container is completely in charge of exactly when an
entity bean instance is created and destroyed. The container instantiates the
bean class using Class.newInstance() so it must have a no-arg constructor.
After this, the container calls the EntityBean.setEntityContext()
method to give the bean instance a reference to it's
javax.ejb.EntityContext that it holds onto until told to let it go. At this
point the bean instance has no identity and moves to the "pooled" state. The
container may choose to create a bunch of bean instances in this way when the
server starts up or it may delay the process until the client needs a bean
instance.
When the client calls a create() method on the entity bean's home
interface, then the first place the container looks is in the pool. If there is no
spare bean instance in the pool it creates one as described above. Next the
container calls the bean instance's matching ejbCreate() method to allow
the bean to perform whatever action is necessary to create the underlying
entity and return a reference to its primary key. If successful, the container
calls the bean instance's ejbPostCreate() method. Now it is attached to the
interposer, has identity and is moved to the "ready" state. The bean instance
can now acquire its state and accept method calls from the client. The bean
class must implement an ejbCreate()/ejbPostCreate() method pair with
matching parameters (type and sequence) for each create() method in the
home interface. All ejbCreate()/ejbPostCreate() calls execute in a
transactional context determined by the call to create() on the home
interface.

504 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

When the client calls a findxxx() method on the entity bean's home
interface then the requested entity bean may already be in use by another
client. If so, the container is at liberty to return a shared reference to the
interceptor for the existing bean instance. In this case the bean already has
identity and there is nothing further for the container to do. If not, the
container looks in the pool and if there is no spare bean instance in the pool it
creates one as described earlier. Next the container calls the entity bean's
matching ejbFindxxx() method to allow the bean to perform whatever
action is necessary to find the underlying entity and return the primary key(s).
After this, the bean stays in the pool with no identity. The bean was merely
used to construct an interceptor to pass back to the client (the interceptor
does know its identity). The entity bean must implement an ejbFindxxx()
method with matching parameters (type and sequence) for each findxxx()
method in the home interface. All ejbFindxxx() calls execute in a
transactional context determined by the call to findxxx() on the home
interface.
If a client calls a method on an entity bean interceptor that is not attached
to an entity bean instance, then the first place the container looks is in the
pool. If there is no spare bean instance in the pool it creates one as described
earlier. The container calls ejbActivate() on the bean instance. Now it is
attached to the interposer, has identity and is moved to the "ready" state.
ejbActivate() runs in an undefined transactional context.
Once in the "ready" state a bean has identity and is mapped to its underlying
entity that may represent read-write data that is shared with other parts of the
system. In order to maintain the consistency of its data the bean instance must
be prepared to synchronize its state with the database at the beginning and
end of every transaction it takes part in. So during its time in the "ready" state
a bean instance will have its ejbLoad() and ejbStore() methods called by
the container many times to indicate that synchronization is required. At this
point, the bean instance must do whatever is necessary to read its data from or
write its data to the underlying data store.
The container can remove the bean instance's identity when it is no longer
required by any client (or perhaps when the container thinks there is a chance
the bean's data is inconsistent). At this time the container calls the entity
bean's ejbPassivate() method. Now it is no longer attached to an
interposer, has no identity and is moved to the "pooled" state.
ejbPassivate() runs in an undefined transactional context.
The entity bean is expected to implement the methods that will be called by
the container during the bean's lifetime to notify it of changes to its state and
of important events in its lifecycle. The different states and the methods are
shown in figure 14.10. Depending on the bean's persistence model, some of
these methods will be implemented by the container and some will be
implemented by the bean class. However, the javax.ejb.EntityBean

Copyright © 2001, DevelopMentor Inc. 505


Module 14: EJB Entities

interface that contains the ejbSetEntityContext(),


ejbUnsetEntityContext(), ejbActivate(), ejbPassivate(),
ejbLoad() and ejbStore() methods must always be implemented by the
bean class.
container loads data:
ejbLoad()
or conta iner saves
ejbyxxx() home
data:
method executes ejbStore()
(EJB 2 only)
create() called on
home interface:
ejbCreate()
ejbPostCreate()
container creates:
Class.newInstance() or container activates:
setEntityContext() ejbActivate()

does not in pool ready


exist (no identity) (identity)
ejbSelect()
conta iner destroys: (EJB 2 CMP
unsetEntityContext() remove() called on
only)
Object.finalize() home/remote interface:
ejbRemove()
or container passivates:
ejbPassivate()

container finds:
method
ejbFindByxxx()
executes
(BMP only)

Figure 14.10: Entity bean class lifecycle

506 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Container-managed persistence
Declarative mapping information tells the container
how to map the bean's data to and from some
persistent entity. The programmer can focus on the
bean's business logic while the container deals with
all aspects of mapping the bean's data to and from
the underlying persistent data store.

Copyright © 2001, DevelopMentor Inc. 507


Module 14: EJB Entities

EJB 1.1 container-managed persistence


Deployment descriptor contains managed fields

• Deployment descriptor also contains vendor-specific mapping information


• Bean's managed fields must be public
• Bean's managed fields must be primitive or serializable types
• Container supplies code to create/delete/find underlying entity
• Container supplies code to load from/store to underlying entity
• Bean class ejbCreate() must initialize managed field values

508 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

The idea of container-managed persistence (CMP) is that the container writes


all the code that accesses the underlying entity in the data store and the
programmer is free to concentrate on writing domain-specific code. Figure
14.11 shows how the container writes the code based on mapping information
provided by the bean. Figure 14.12 shows how things look at runtime.
public class CustomerEntityBean <ejb-jar>
extends EntityBean { <enterprise-beans>
public int id; <entity>
public String name; <!-- managed fields, primary key -->
public int age; </entity>
public String getName() </enterprise-beans>
{return name;} </ejb-jar> <container-specific>
public void setName(String n)
<!-- All details of dependent objects,
{name=n;}
entity relationships,

// primary key dependent object relationship and
}
mapping of managed
public class CustomerEntityPK … {
public int id; fields/relationships is
… container-specific -->
} </container-specific >

Container
deployment tool

Deployer
Container-generated
data access code

Figure 14.11: EJB 1.1 CMP deployment

Container-generated
public class CustomerEntityBean … {
r public int id; interposer
e public String name;
m public int age;
o public String getName()
t {return name;}
e public void setName(String n)
{name=n;} Container-generated
I …
n } data access code
t
e
r EntityContext.getPrimaryKey()
f
a
Instance of CustomerEntityPK
c
id=0002
e

CUSTOMER table CID CNAME CADDRESS CAGE

0001 John Smith 1 H ill Vie w, Chelte nham 47

0002 Mary Ba rnes34 Beacon Rd, Gloucester 22

0003 Kevin Jones 3 Sheep St, Wellington 39

Figure 14.12: EJB 1.1 CMP at runtime

Copyright © 2001, DevelopMentor Inc. 509


Module 14: EJB Entities

The EJB 1.1 specification mandates that the entity bean class supplies a list of
its fields that the container will manage on its behalf. This information goes in
the deployment descriptor along with the entity bean's primary key class.
Figure 14.13 illustrates. The details of how the bean class's managed fields are
actually mapped to the underlying entity is completely vendor-specific.
Commonly the vendor supplies an object-relational mapping tool that simply
associates the bean class's members with columns in a database table, but it
may provide for a more comprehensive object modeling tool.
<ejb-jar>
<enterprise-beans>
<entity>
...
<transaction-type>Container</transaction-type>
<persistence-type>Container</persistence-type>
<prim-key-class>CustomerEntityPK</prim-key-class>
<cmp-field><field-name>id</field-name></cmp-field>
<cmp-field><field-name>name</field-name></cmp-field>
<cmp-field><field-name>age</field-name></cmp-field>
</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>CustomerEntity</ejb-name>
<method-intf>Remote</method-intf>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
Figure 14.13: Entity bean deployment descriptor for EJB 1.1 CMP

The bean's managed fields must be public and either primitive or serializable
types. A reference to another bean or its remote interface is valid but it is
completely dependent on the container how this relationship will be persisted.
Commonly the container will persist the referenced bean's handle to the
database as a blob but some containers do provide a way of transparently
storing object graphs. The class definition is shown in figure 14.14. The fields
of the primary key class must be a subset of the associated bean class's
managed fields.

510 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

import javax.ejb.*;

public class CustomerEntityBean implements EntityBean


{
public int id; public String name; public int age;
private EntityContext ctx;

// Methods corresponding to create() in home interface


public CustomerEntityPK ejbCreate(int id, String name,
int age){
this.id=id;this.name=name;this.age=age; return null; }
public void ejbPostCreate(int id, String name, int age){}

// Methods mandated by EntityBean interface


public void setEntityContext(EntityContext ctx)
{this.ctx=ctx;}
public void unsetEntityContext(){ this.ctx=null; }
public void ejbRemove(){}
public ejbActivate(){} public ejbPassivate(){}
public ejbLoad(){} public ejbStore(){}

// Methods corresponding to remote interface


public int getID(){ return id; }
public String getName(){ return name; }
public int setName(String name){ this.name=name; }
}
Figure 14.14: Entity bean class for EJB 1.1 CMP

When the client calls a create() method in the entity bean's home interface,
the container will create the underlying entity, e.g. insert a record in the
database. The container creates a new instance of the bean class or acquires
one from the pool. It then calls the matching ejbCreate() method of the
bean instance, passing in the parameters from the create() call. This allows
the bean instance to initialize its managed fields. On the return from the
ejbCreate() the container uses the values of the bean instance's managed
fields and the information that maps the bean class's managed fields to the
underlying datastore to insert the entity. For CMP the ejbCreate() method
returns a null primary key as the container generates a primary key based on
the bean class's mapping information. If the ejbCreate() method threw an
exception then the underlying entity would not be created and an error
returned to the client. After the container has inserted the underlying entity
and generated the primary key and associated it with the bean's interceptor, it
calls the matching ejbPostCreate() method of the bean instance at which
point the bean has identity.

Copyright © 2001, DevelopMentor Inc. 511


Module 14: EJB Entities

The bean class does not have to implement any ejbFindxxx() methods
matching the findByxxx methods in the home interface as these will be
provided by the container based on some vendor-specific syntax.
The container also writes all the code to synchronize data with the
underlying data store based on the bean's managed field mappings. The bean
instance's ejbLoad() and ejbStore() methods, mandated by the
javax.ejb.EntityBean interface, are called by the container just after
data has been read from the underlying datastore and just before data is
written to the underlying datastore. The bean does not have to do anything in
the body of these two methods but it could. Having the container manage some
of the bean's fields doesn't mean it has to manage all of them. The ejbLoad()
and ejbStore() methods would be the place to provide custom data access
code or to reformat fields before and after the container stores and loads
managed fields on behalf of the bean.
If the client calls EJBObject.remove() or EJBHome.remove() on an
entity bean then the container will call the bean's ejbRemove() method. If it
doesn't throw an exception then the container will remove the entity from the
underlying datastore.

512 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

EJB 2.0 container-managed persistence


Pluggable persistence manager and well-defined bean persistence schema

• Can define dependent objects


• Can define relationships
• Common query syntax (EJB QL)
• For "finders" on home and "selectors" on bean
• All this makes CMP beans more portable
• Container can do better job of managing object graphs?

514 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

The EJB 1.1 container-managed persistence model does not prescribe very
much. All it mandates is that the bean's deployment descriptor detail the bean
fields to be managed by the container, and that the bean class and associated
primary key class follow a few simple rules. All other details are provided by
the deployer based on a container's object mapping tool. All details of the
persistence manager (used to map an entity graph to an underlying datastore)
and all details of the persistence schema (used to determine exactly how to
map an entity graph to an underlying datastore) are completely container-
specific. For instance, some containers have excellent support for defining and
maintaining relationships between entities and some do not. This means that it
depends on which container an entity bean is deployed in as to whether it has
to write special code to maintain these relationships or not.
When a developer first encounters entity beans they are tempted to make
each piece of persistent data into one, leading to entity bean bloat and bad
performance. Many would-be entity beans are in fact "dependent" objects. A
dependent object is, broadly speaking, one whose lifetime and meaning is
determined entirely by some entity bean (or some other dependent object) and
whose interface never needs to be exposed to remote clients. It is better
implemented as a regular Java class that relies on its surrounding entity to
access its underlying data and populate it accordingly. One example, provided
in the EJB specification, is that of a purchase order that is represented as an
entity bean but whose individual line items are be dependent objects. The
purchase order would go out and perform one or two queries to obtain its data
and that of all its associated line items and then build and populate an internal
object graph. The line items only make sense within the context of the
purchase order. Deleting the purchase order causes the line items to be
deleted--a cascading delete. Again, some containers have support for defining
dependent objects and maintaining relationships between entities and
dependent objects and some do not. This means that it depends on which
container an entity bean is deployed in as to whether it has to write special
code to maintain these dependent objects and their relationships or not.
These are just two of many problems that lead to non-portable code, which
flies in the face of the EJB model. EJB 2.0 addresses some of these common
problem areas and introduces a new CMP model that is completely different
from EJB 1.1. However, EJB 2.0 servers must still support the EJB 1.1 CMP
model for backwards compatibility. In EJB 2.0 the persistence manager has
been culled out as a new participant, independent from the container. There is
a formal contract between the persistence manager and the entity bean (called
the bean's "abstract persistence schema") that is defined in the bean's
deployment descriptor. Over and above the managed field list that existed for
EJB 1.1 CMP beans it provides a detailed description of any dependent objects
used by the bean and the relationships it has with them and other entity beans.
The persistence manager uses this information to build data access code that
maps the entity bean data and its relationships to the underlying datastore as
shown in figure 14.15. The contract between the container and the persistence

Copyright © 2001, DevelopMentor Inc. 515


Module 14: EJB Entities

manager will evolve to allow the persistence manager to be written by a


container or some other third-party vendor specializing in object mapping (such
as a database vendor), so persistence managers can work with different
containers and thus allows entity beans to become more portable across EJB
vendors and persistence managers.
public abstract class CustomerEntityBean <ejb-jar>
extends EntityBean { <enterprise-beans>
public abstract String getName(); <entity>
public abstract void setName(String n); <!-- managed fields, primary key -->
public abstract Address getAddress(); </entity>
public abstract void setAddress(Address a); </enterprise-beans>
… <dependents>
} public abstract class Address … { …
public abstract String getStreet(); </dependents>
public abstract void setStreet(String s); <relationships>
… …
// primary key
} </relationships>
public class CustomerEntityPK … {
public int id; </ejb-jar>
<container-specific>
… <!-- All details of
} mapping managed
fields/relationships
is still
container-specific -->
Persistence Manager </container-specific >

deployment tool

Deployer

Persistence Manager-generated
data access code

Figure 14.15: EJB 2.0 CMP deployment

The bean's abstract persistence schema is mirrored by the bean class and its
dependent object classes. They are all abstract base classes, and their
persistent and relationship fields are accessed using abstract getter and setter
methods whose method signatures are dictated by information in the bean's
abstract persistence schema. Whenever the bean or one of its dependent
objects needs to access a persistent field or a relationship, then it must use
these methods. At deployment time the persistence manager tool uses the
bean's abstract persistence scheme to generate a concrete implementation of
the abstract bean class and the abstract dependent object classes. Figure 14.16
shows this. The getters and setters can be exposed as part of the remote
interface of an entity bean only if they do not provide access to dependent
objects.

516 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

public abstract class CustomerEntityBean public abstract class Address


extends EntityBean { implements Serializable {
public abstract Address getAddress(); public abstract String getStreet();
public abstract void setAddress(Address a); public abstract void setStreet(String s);
public abstract int getId(); …
public abstract void setId(int id); }
public abstract String getName();
public abstract void setName(String n);

} public class RealAddress
extends Address {
public String getStreet() {…}
public class RealCustomerEntityBean public void setStreet(String s) {…}
extends CustomerEntityBean { …
public Address getAddress(){…} }
public void setAddress(Address a) {…}
public int getId() {…}
public void setId(Int id) {…}
public String getName() {…}
public void setName(String n) {…}

}

CID CNAME CADDRESS CAGE

0001 John Smith 1 Hill Vie w, Chelte nham 47


CUSTOME R table
0002 Mary Barnes 34 Beacon Rd, Gloucester 22

0003 Kevin Jones 3 Sheep St, We llington 39

Figure 14.16: EJB 2.0 CMP generated code

The concrete bean class is instantiated by the container to represent the bean
at runtime. It maintains the specified relationships and has implementations of
the getter/setter methods that will actually read and write the bean's state
and relationships to the underlying datastore. Likewise, the concrete
dependent object classes are instantiated by the container to represent the
bean's dependent objects. They too maintain any specified relationships and
have implementations of the getter/setter methods that will read and write
the dependent object's state and relationships to the underlying datastore.
Figure 14.17 shows how things look at runtime.

Copyright © 2001, DevelopMentor Inc. 517


Module 14: EJB Entities

public abstract class CustomerEntityBean … { Container-generated


r
public abstract String getName(); interposer
public abstract void setName(String n);
e …
m } public abstract class Address … {
o public abstract String getStreet();
t public abstract void setStreet(String s);
e …
}
I
n
t
e Persistence manager-generated
EntityContext.getPrimaryKey()
r
f data access code
a
Instance of CustomerEntityPK
c
id=0002
e

CID CNAME CADDRESS CAGE

0001 John Smith 1 Hill Vie w, Chelte nham 47

0002 Mary Barnes 34 Beacon Rd, Gloucester 22

0003 Kevin Jones 3 Sheep St, We llington 39

Figure 14.17: EJB 2.0 CMP at runtime

The abstract bean class is shown in more detail in figure 14.18 and the
dependent object class in 14.19. The dependent object is described in the
bean's deployment descriptor as shown in figure 14.20 and the relationship
between the bean class and the dependent object is also described in the
bean's deployment descriptor as shown in figure 14.21. Dependent object
classes are only visible to the entity bean, and so cannot form part of the
bean's remote interface either as a parameter or a return type. Although not
shown here, relationships can also be expressed between one entity bean
another and between one dependent object and another. Also more complex
one-to-many and many-to-one relationships can be described, both
unidirectional and bi-directional. A one-to-many relationship with an entity
bean or a dependent object is represented as either a
java.util.Collection or java.util.Set type. A one-to-one relationship
with a dependent object uses the dependent object's type and a one-to-one
relationship with an entity bean uses the entity bean's remote interface type.

518 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

import javax.ejb.*;

// Only deltas from EJB CMP 1.1 shown


public abstract class CustomerEntityBean implements
EntityBean {
...
// Methods corresponding to create() in home interface
public CustomerEntityPK ejbCreate(String name, int age){
setId(id); setName(name); setAge(); return null; }
...
// Methods mandated by EntityBean interface
...
// Abstract getter/setter methods for managed fields
// Some may correspond to those in remote interface
public abstract int getId();
public abstract void setId(int id);
public abstract String getName();
public abstract void setName(String n);
public abstract int getAge();
public abstract void setAge(int a);
public abstract Address getAddress();
public abstract void setAddress(Address a);
...
}
Figure 14.18: Entity bean class for EJB 2.0 CMP

import java.io.*;

public abstract class Address implements Serializable {


// Abstract getter/setter methods for managed fields
public abstract String getStreet();
public abstract void setStreet(String s);
public abstract String getPostCode();
public abstract void setPostCode(String p);
...
}
Figure 14.19: Dependent object class for EJB 2.0 CMP

Copyright © 2001, DevelopMentor Inc. 519


Module 14: EJB Entities

<ejb-jar>
<enterprise-beans>
<entity>
<!-- Same as EJB 1.1 CMP settings
(managed fields, primary key etc)-->
</entity>
</enterprise-beans>
<assembly-descriptor>
<!-- Same as EJB 1.1 CMP settings
(transaction attributes etc) -->
</assembly-descriptor>
<dependents>
<dependent>
<description>Address dependent class</description>
<dependent-class>Address</dependent-class>
<dependent-name>Address</dependent-name>
<cmp-field><field-name>street</field-name></cmp-
field>
<cmp-field><field-name>postCode</field-name></cmp-
field>
</dependent>
</dependents>
...
</ejb-jar>
Figure 14.20: Entity bean deployment descriptor for EJB 2.0 CMP

520 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

<ejb-jar>
...
<relationships>
<ejb-relation>
<ejb-relationship-name>Customer-Address</ejb-
relationship-name>
<ejb-relationship-role>
<ejb-relationship-role-name>customer-has-address
</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<role-source><ejb-name>Customer</ejb-name></role-
source>
<cmr-field>
<cmr-field-name>address</cmr-field-name>
<cmr-field-type>Address</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>address-belongs-to-
customer
</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<role-source><dependent-name>Address</dependent-
name></role-source>
</ejb-relationship-role>
</ejb-relation>
</relationships>
...
</ejb-jar>
Figure 14.21: Entity bean deployment descriptor for EJB 2.0 CMP

EJB Query Language (EJB QL), based on SQL-92, provides a syntax that allows
finder queries to be specified in a portable fashion. The persistence manager
uses EJB QL queries to implement that code that sits behind the finder
methods in the home interface and private finder methods that the bean
implementation can use. The query required to execute the mandatory
findByPrimaryKey() from an entity bean's home interface uses the field(s)
of the primary key to lookup the entity data in the datastore. No EJB QL
statement is needed as this is implicit. Given the earlier home interface
definition, the EJB QL needed to specify the query for the
findWhereAgeGreaterThan() is shown in figure 14.22. The SELECT clause,
which indicates what entity bean type to select, is not needed in the EJB QL
statements for finder methods because they always return the bean's own type
or collections of the bean's own type.

Copyright © 2001, DevelopMentor Inc. 521


Module 14: EJB Entities

<ejb-jar>
<enterprise-beans>
<entity>
...
<query>
<query-method>
<method-name>findWhereAgeGreaterThan</method-
name>
<method-params>int</method-params>
</query-method>
<!-- where age>?1 -- >
<ejb-ql>where age&gt;?1</ejb-ql>
</query>
<!-- finder for findByPrimaryKey() not needed -- >
...
</entity>
</enterprise-beans>
...
</ejb-jar>
Figure 14.22: EJB QL deployment descriptor finder syntax

However, it is possible to use the SELECT clause when defining a select


method in an entity bean class. Select methods take the form
ejbSelect<type> and ejbSelect<type>InEntity and are similar to
finder methods in the home interface except that a) they are not declared in
the home interface and therefore not exposed to the client--they are only for
the bean class itself to use and b) they are not restricted to just returning the
bean's own remote interface type. An example is given in 14.23. The
Customer entity bean now contains many dependent Account objects.
ejbSelect<type> methods execute in a global context, i.e. not specific to
the bean instance on which it is executed. That means the
ejbSelectAccounts method returns all accounts with a minimum balance
for all customers. ejbSelect<type>InEntity methods execute within the
context of the entity bean instance on which they are executed. That means
the ejbSelectAccountsInEntity method returns all accounts with a
minimum balance for this customer. The select methods are declared as
abstract methods in the bean class and are used only within the bean class
implementation. The persistence manager provides concrete implementations
based on settings in the deployment descriptor shown in 14.24. Figure 14.23
shows how a home method might use a selector.

522 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

public abstract class CustomerEntityBean implements


EntityBean {
...
public int ejbHomeNumAccounts (int bal ){
Collection col = ejbSelectAccouts(bal);
return col.size();
}
...
// Abstract getter/setter methods for managed fields
public abstract Collection getAccounts();
// Get all accounts for this customer with more than
'bal'
public abstract Collection ejbSelectAccountsInEntity(int
bal);
// Get all accounts for all customers with more than
'bal'
public abstract Collection ejbSelectAccounts(int bal);
...
}
...
public abstract class Account implements Serializable {
// Abstract getter/setter methods for managed fields
public abstract int getBalance();
...
}
Figure 14.23: EJB QL example code

Copyright © 2001, DevelopMentor Inc. 523


Module 14: EJB Entities

<ejb-jar>
<enterprise-beans>
<entity>
...
<query>
<query-method>
<method-name>ejbSelectAccountsInEntity</method-
name>
<method-params>int</method-params>
</query-method>
<!-- select a from a in accounts where
a.balance>?1 -->
<ejb-ql>select a from a in accounts where
a.balance&gt;?1</ejb-ql>
</query>
<query>
<query-method>
<method-name>ejbSelectAccounts</method-name>
<method-params>int</method-params>
</query-method>
<!-- select a from a in accounts where
a.balance>?1 -->
<ejb-ql>select a from a in accounts where
a.balance&gt;?1</ejb-ql>
</query>
</entity>
</enterprise-beans>
...
</ejb-jar>
Figure 14.24: EJB QL deployment descriptor selector syntax

524 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Bean-managed persistence
Container-managed persistence may have
limitations. Allowing the bean to implement its own
persistent mechanism overcomes some limitations
while maintaining the same programming interface
to the client.

Copyright © 2001, DevelopMentor Inc. 525


Module 14: EJB Entities

Bean-managed persistence
Bean class implements all data access code

• Can have more flexible mapping to underlying datastore


• No mapping info in deployment descriptor
• Bean environment may encode some data access info, e.g. connection string
• ejbCreate() needed for each create() in home
• Creates entity data in datastore and generates primary key
• ejbFindxxx() needed for each findxxx() in home
• Finds entity(ies) in datastore and returns primary key(s)
• ejbRemove() deletes entity data from datastore
• ejbLoad()/ejbStore() sync with entity data in datastore
• Can provide optimizations

526 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Container-managed persistence can be fairly limiting. The EJB specification


does not specify how the container should map an entity bean to its underlying
data. Perhaps this is understandable as, if it did, this would severely restrict
the container vendor from innovating. However, the EJB container's mapping
syntax may not support your requirements. What if it only supports mapping
entity beans against a database and your data is stored on the file system or in
a legacy system? What if it only supports mapping an entity bean to a single
table but your entity data is the result of a complex join between tables? What
if it only supports mapping an entity bean to a single row but your entity data
represents a collection? In these cases the only real choice is to have the bean
class manage its own data access code--bean-managed persistence. When the
bean class implements the data access code it can provide any kind of mapping
to any kind of datastore.
The bean class is on the hook for writing all data access code to interface to
the entity in the underlying datastore. This means the code to create/delete
the entity data, find entity data based on some client-supplied criteria and
load/store the entity data. Figure 14.25 illustrates. In the case where the
underlying datastore is a database, this means using a Java data access API
such as JDBC.

Copyright © 2001, DevelopMentor Inc. 527


Module 14: EJB Entities

import javax.ejb.*;

// Only CMP deltas shown


public class CustomerEntityBean implements EntityBean {
private int id; private String name; private int age;
boolean isDirty;
public CustomerEntityPK ejbCreate(int id, String name,
int age){
this.id=id;this.name=name;this.age=age;
CustomerEntityPK pk = new CustomerEntityPK();
insertRecord(id, name, age); pk.id = id; return pk; }

public CustomerEntityPK
ejbFindByPrimaryKey(CustomerEntityPK pk)
{ findRecord(pk.id); return pk; }
public Enumeration ejbFindWhereAgeGreaterThan(int age){
CustomerEntityPk pk[] = findRecordsByAge(age);
return toEnumeration(pk[]); }

public void ejbActivate(){


id=((CustomerEntityPK)ctx.getPrimaryKey()).id; }
public void ejbRemove(){ removeRecord(); }
public ejbLoad(){ loadRecord(); }
public ejbStore(){if (isDirty) storeRecord();
isDirty=false;}

public int setName(String name){


this.name=name;isDirty=true; }
...
}
Figure 14.25: Entity bean class for BMP

The client of the entity bean never knows which persistence mechanism is used
as its access to the bean is always via the remote interface. The bean's
concurrency model is exactly the same as for CMP and from the bean class's
perspective its lifecycle is the same too.
There is no need for the bean to provide information about managed fields
or class-level mapping in the deployment descriptor as for CMP, but it must still
contain the association between the bean and its primary key. However, it is
likely that the bean may want to use its environment to store information used
by its implementation, such as the connection string. In fact, it would be
possible for the bean implementation to be generated from the bean's own
proprietary mapping information defined in a syntax that supports all the beans
needs.

528 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

The bean class must supply an ejbCreate()/ ejbPostCreate() method


that corresponds to each create() method on the home interface. Each
ejbCreate() method must create the underlying entity, using the parameters
passed in from the client's call to the corresponding create() method, and
also create and return a primary key that the container will associate with the
interceptor.
The bean class must supply an ejbFindxxx() method that corresponds to
each findxxx() method on the home interface (including
findByPrimaryKey()). Each ejbFindxxx() method must find the one or
more underlying entities, using the parameters passed in from the client's call
to the corresponding findxxx() method, and also create and return one or
more primary keys that the container will associate with the interceptor(s).
Finders that result in multiple entities being found return multiple primary keys
in a java.util.Enumeration or a java.util.Collection.
The bean class ejbLoad() and ejbStore() methods must load the entity
data from or store the entity data to the underlying datastore. Note that this
should never be done in ejbActivate() or ejbPassivate() as these run in
an undefined transactional context. The ejbLoad() and ejbStore()
methods are only ever called when the bean is in the "ready state" and has
identity (but never during a method call). Thus the bean class code can deduce
its identity and which underlying entity it represents by calling
javax.ejb.EntityContext.getPrimaryKey() to acquire the primary key
associated with its interceptor. Certain optimizations can be performed in the
ejbLoad() and ejbStore() methods such as only writing back data if it has
been changed and only reloading data if you know it may have changed.
The bean class ejbRemove() method must delete the entity data from the
underlying datastore.

Copyright © 2001, DevelopMentor Inc. 529


Module 14: EJB Entities

Issues with entities


Decomposing a task into small components is
dangerous when each component needs to fetch and
store its data independently. Naive use of entities
causes such round-trip problems.

Copyright © 2001, DevelopMentor Inc. 531


Module 14: EJB Entities

The danger of entities


Composing any objects that hide round-trips is dangerous

• Entity bean is in-memory representation of persistent data


• Entity bean and its data may be remote--round trips
• Read-write, shared entities must be accessed under a transaction for
consistency
• Entity data must be read at start of transaction
• Entity data may have to be written at end of transaction
• Naive entities will kill scalability/performance
• Deadlock also a potential problem

532 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Entity beans represent an in-memory representation of data held in a


persistent datastore. Often the EJB container that executes the entity bean is
on a different machine to the datastore. That means there is a round-trip every
time an entity bean needs to load its data from the datastore or store its data
to the datastore. Entity beans that represent shared, read-write data must be
accessed within a transaction to remain consistent. Every time an entity is first
accessed within a transaction it needs to load its data from the datastore in
case the underlying entity data has been updated by another part of the system
and the in-memory representation is stale. At the end of every transaction,
every entity bean that has been updated in memory needs to flush its changes
back to the datastore so that they are persistently stored and so other parts of
the system can see the changes. This means that every entity bean used in a
transaction can result in two round-trips. Imagine a transacted middle-tier
operation that uses a thousand entities and you soon get an idea of the
problem. Given that the longer a transacted operation takes to run the longer
it holds locks and the worse is the throughput and scalability, what can be
done?

Copyright © 2001, DevelopMentor Inc. 533


Module 14: EJB Entities

Some possible solutions


Prefer performance over OO

• Some containers run alongside database


• Some containers do middle-tier caching
• Smart containers avoid round-trips, deadlock using bean hints
• Non compliant : BMP the only sure way
• Don't use entities remotely (certainly not from client)
• Use bulk setters/accessors if entities must be accessed remotely
• Better design : coarse grained entities, fine-grained dependent objects
• Avoid entities : stored procedures?

534 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

EJB containers provided by database vendors, such as Oracle, can ensure that
their container runs on the same machine as the database machine and, in
fact, that the entities are stored directly in the database. This negates the
round-trip problem but only works with that vendor's EJB container and that
vendor's database, thus forcing vendor lock-in. It also loses any advantages that
can be gained by having the middle-tier application server and the database
server as different machines. Some EJB container vendors, such as Persistence
Software, claim to support efficient middle-tier caching solutions where the
cache is intelligent enough to reduce the round-trips needed to the back-end
datastore or other middle-tier caches in the same server farm. Your mileage
may vary with these and, again, this solution suffers from lock-in to that
vendor's EJB container.
Some containers are smarter than others and can figure out when to load
and store data. For instance, the Weblogic container allows the bean code to
supply a programmatic means by which the container can discover if an entity
is dirty and thus whether it needs to store an entity bean's data at the end of
the transaction. The Weblogic container also allows the bean to supply a
declarative setting that specifies whether it is read-only or not shared with any
other part of the system and this influences how often the container needs to
load the entity bean's data. None of these tricks is covered by the EJB
specification and so won't necessarily work with all containers.
Obviously an entity that uses BMP can play all of these tricks if it wants. It is
easy for such an entity bean to figure out that it doesn't need to update data
that hasn't changed at the end of the transactions or to avoid loading data
when first used in a transaction because it is not shared within the system or
because it only supports update functionality.
Entities that do follow a read-for-update pattern within a transaction do run
the risk of deadlock. Imagine two entities accessing the same underlying data
running concurrently within different transactions. When first accessed within
the transaction, they both read their underlying data, taking a shared read lock
in the database. At the end of the transaction they both need to store their
data to the database and so attempt to acquire an exclusive write lock. Each
blocks the other and so deadlock ensues. What is required is a SQL "READ ...
FOR UPDATE" statement that says to the database "I am reading this data now
but will be updating it later". This forces the database to effectively take an
exclusive lock on the data so only one transaction gets to read. If the
container's CMP syntax does not support this feature then BMP could be used
instead.
It may be possible to reduce the number of round-trips (queries and/or
updates) with a better design. Use of dependent objects can help if used
correctly. Recall that a dependent object is one whose lifetime and meaning is
determined entirely by some entity bean (or some other dependent object) and
whose interface never needs to be exposed to remote clients. It is
implemented as a regular Java class that relies on its surrounding entity to

Copyright © 2001, DevelopMentor Inc. 535


Module 14: EJB Entities

access its underlying data and populate it accordingly. This is beneficial for two
reasons. First, it means that the entity can interact with the underlying
datastore in an efficient manner to serialize and deserialize a graph of
dependent objects. Second, calling the dependent object does not incur the
overhead of calling an entity bean. Even though some containers will optimize
non-remote calls to beans, there still may be significant overhead.
If possible, entities should not be accessed remotely else this will incur the
overhead of an RMI call and the associated round-trip. Entities that represent
shared, read-write data should never be passed back to a remote base EJB
client as this puts the onus on the client to supply a) the logic to manipulate
the entity (defeating the point of the middle tier) and b) the transaction
needed by the entities. Such entities are best called "locally" from an EJB
session bean or JSP/Servlet running in the middle-tier. If it is unavoidable that
an entity bean be called remotely within the middle-tier then the provision of
bulk accessors on the entity's remote interface, rather than field-by-field
accessors, would help reduce the overhead.
To reduce round-trips to a minimum, it seems that in most cases bean-
managed persistence has to be used as it allows the developer the flexibility to
make more intelligent decisions than the container could. To be really extreme
it would be possible to avoid entities altogether and perform all data access
with a stored procedure in the database. Again, because of the varied nature
of stored procedure syntax this does provide lock-in to a given vendor's
database. However, it would have the advantage of being able to execute all
logic within a single round-trip and execute the transaction inside the stored
procedure, thus removing the time taken by the round-trip from the overall
transaction time.

536 Copyright © 2001, DevelopMentor Inc.


Module 14: EJB Entities

Summary
• In-memory representation of persistent, read-write, shared data
• Identity defined by a primary key
• Two models for managing persistence: Container-managed and Bean-
managed
• Accessed under a transaction
• Container provides isolation in memory where required
• Naive use of entities can hurt scalability

Copyright © 2001, DevelopMentor Inc. 537


Module 15

XSLT

Copyright © 2001, DevelopMentor Inc. 539


After completing this module, you should be able to:
 understand how XSLT is used to transform between different XML
dialects and into other formats
 feel comfortable with XSLT syntax
 appreciate the power of the declarative template programming style
 write Java code to run XSL transforms

540 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

Extensible Stylesheet Language:


Transformations ( XSLT )
XSLT is an XML vocabulary for expressing
transformations. An XSL transform takes an XML
infoset and turns it into another XML infoset or
some other textual format.

Copyright © 2001, DevelopMentor Inc. 541


Module 15: XSLT

What is XSLT?
Often need to convert XML into "something else"

• XML APIs like SAX, DOM are cumbersome


• XSLT is an XML grammar designed solely to express transforms
• Transform operates on XML infoset input and emits XML infoset or text
• Transforms describe a set of rules for transforming the input XML infoset
• XSLT instructions are elements/attributes from
http://www.w3.org/1999/XSL/Transform namespace
• XSLT 1.0 a W3C recommendation, XSLT 1.1 is a W3C working draft

542 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

XML provides facilities for structuring documents and data. Often, XML-based
information needs to be converted into some other format. Converting to HTML
for display in a web browser is a common example. Converting to a different
XML format, perhaps using elements in place of attributes or using a different
namespace, is another. This kind of conversion is often necessary when
accepting information from outside sources; in order to make the data more
amenable to processing it must first be converted. Generating program source
code such as Java or C# from XML, typically some kind of schema, is yet
another kind of conversion. Any and each of these conversions is essentially a
transformation of the initial XML tree. Such transformations can be performed
using standard XML APIs such as SAX or DOM. For example, a program could
load an XML document into a DOM and then walk through the DOM tree and
write alternative output to a stream, or, if the output was to be XML or HTML,
to another DOM. Alternatively, the Extensible Stylesheet Language:
Transformations ( XSLT ) offers a powerful alternative that frees the author of
the transformation from having to write complex DOM navigation code or
implement a SAX ContentHandler, allowing them to concentrate instead on the
details of the transformation.
XSLT is a language for expressing transformations. A transform takes an XML
infoset as input, operates on it, and produces output. The output, also called a
result tree, may be another XML infoset, HTML or any other text format. A
transform is expressed using elements and attributes from the
http://www.w3.org/1999/XSL/Transform namespace as defined in the
XSLT specification. Thus the transform itself is also an XML infoset. Figure 15.1
shows the input and output from a transform.

XSL Transform Output


Input XML
(also an XML (text or XML
infoset
infoset) infoset)

Figure 15.1: XSLT Processing

In order to process a transform an XSLT processor is needed. Several are


available including Microsoft's MSXML 3.0, Apache's Xalan, Michael Kay's Saxon
and James Clark's XT. Technically, an XSLT processor may run on top of a DOM
or SAX parser. There are always two initial inputs to any XSLT processor and a
single output as shown in figure 15.2. The inputs are the source XML infoset
and the transform while the output is the result tree generated by the
templates in the transform. Consult the documentation for a given parser for
details of how to specify the inputs and outputs for that parser. Details of how
to run the Xalan processor from the command-line and from Java code are
given later in the module.

Copyright © 2001, DevelopMentor Inc. 543


Module 15: XSLT

Input XML
Infoset

XSLT
Output
Processor

Transform

Figure 15.2: Input and output of an XSLT Processor

544 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

XSLT basics
Transform adopts an exemplar-based, declarative approach

• Transform broken into one or more templates


• Named templates execute when called explicitly
• Other templates execute when pattern matched in input infoset
• Processing starts with templates that matches input infoset document root
• XPath is "pattern matching" language used to locate items from input infoset
• Template content used to produce output
• Template content is mixture of static text and dynamically executed XSL
instructions

546 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

Figure 15.3 shows a simple transform, and how it translates the input XML
infoset to the output XML infoset. The document element is xsl:transform
where the xsl prefix maps to the
http://www.w3.org/1999/XSL/Transform namespace name. The local
name stylesheet may be used in place of transform. Regardless of
whether transform or stylesheet is used there must be an unqualified
version attribute with a value of 1.0 (1.0 for an XSLT 1.1 transform).
<?xml version="1.0" encoding="UTF-8"?>
<people>
<person name='Martin' age='33' />
<person name='Hayley' age='30' />
<person name='Matthew' age='6' />
<person name='Samuel' age='4' />
</people>

<?xml version="1.0" encoding="UTF-8"?>


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<doc>hello world!</doc>
</xsl:template>
</xsl:stylesheet>

<?xml version="1.0" encoding="UTF-8"?>


<doc>hello world!</doc>

Figure 15.3: A simple transform--Hello world!

A transform is made up of one or more templates, each template producing


part of the output of the transform. A template is typically a mixture of static
output and XSLT instructions. Static output is text that is written directly to
the result tree. XSLT instructions are evaluated as they are encountered and
may produce dynamically generated output to the result tree. Processing
always begins at the template instruction that selects the XML source
document's document information item. Note that this is the document node,
not the document element! In this example, the only child of the
xsl:transform element is a xsl:template element with a match attribute
whose value is /. The value of the match attribute is, broadly speaking, an
XPath expression, and in this case matches the document root of the input
infoset. Many of the XSLT constructs used to described transformation rules use
XPath expressions as part of their syntax. Indeed, XPath is the foundation on
which XSLT, and thus transforms themselves are built. In the case of a single
template transform, such as this, one template produces all of the output.
Notice also that, in this case, the output XML infoset from the transform is

Copyright © 2001, DevelopMentor Inc. 547


Module 15: XSLT

completely independent from the input XML infoset. This is because the
content of the transform comprises only static text--there are no XSL
instructions that use the input XML infoset to influence the outcome XML
infoset.

548 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

XSLT syntax (1)


Basic XSLT syntax

• XPath expressions evaluated relative to current context


• Extracting values from the input infoset
• Literal result elements
• Looping
• Sorting
• Conditional evaluation
• Dynamic creation of items in the output infoset

550 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

The xsl:value-of instruction is used to evaluate expressions. Like all XSLT


instructions the value-of element is in the
http://www.w3.org/1999/XSL/Transform namespace. The xsl:value-
of instruction takes a select attribute whose value is an XPath expression.
Typically such expressions are used to extract items from the input infoset. The
expression may be an absolute or relative XPath expression or an XPath
function such as sum. Relative expressions are evaluated relative to the current
context, just as in standard XPath outside of XSLT. The current context consists
of a current node-list, a current node within that node-list, a context position
(the current position of the current node in the current node list : a 1-based
collection) and a context size (the number of elements in the current node
list). In the example shown in figure 15.4 the xsl:value-of instructions are
being executed within the template that matched the document root of the
input XML infoset, and in this case the context node is the document root of
the input XML infoset, the context position is 1 and the context size is 1. More
on context when we look at multi-template programming and constructs such
as xsl:for-eaxh later in the module. The xsl:value-of instruction is
replaced in the output stream by the result of evaluating the expression and
converting it to a string. Given that the job of a transform is to produce output
based on the input infoset the xsl:value-of instruction is often the most
common XSLT instruction in a transform.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<person>
<name><xsl:value-of select='people/person/@name' /></name>
<age><xsl:value-of select='people/person/@age' /></age>
</person>
</xsl:template>
</xsl:transform>

<?xml version="1.0" encoding="UTF-8"?>


<person>
<name>Martin</name>
<age>33</age>
</person>

Figure 15.4: xsl:value-of example

Each of the elements in the transform that are not in the XSLT namespace are
known as Literal Result Elements. In the 15.4 example the person, name and
age elements fall into this category. The content of a Literal Result Element
may include static text, dynamically evaluated XSLT instructions and other

Copyright © 2001, DevelopMentor Inc. 551


Module 15: XSLT

Literal Result Elements. Each such element is emitted, along with the output
implied by its content, as output. The XSLT instructions, in this case the two
xsl:value-of elements are replaced with their dynamically evaluated result.
Any single template transform whose output is either an XML Infoset or HTML
can be converted into a Literal Result Element Transform. Such a transform
uses the content of the single template as the transform itself. Thus the
transform looks like the output apart from the presence of XSLT instructions.
The top-level element of such a transform must be annotated with a version
attribute in the XSLT namespace with a value of 1.0. The presence of this
qualified attribute signals to the XSLT processor that this is a transform despite
not having xsl:transform or xsl:stylesheet as the top level element.
Note that the version attribute is unqualified in the standard transform case
because the document element, xsl:transform or xsl:stylesheet is in
the XSLT namespace.
Thus the simple transform shown above in figure 15.5 can be rewritten as
the Literal Result Element Transform shown below. This style of transform
looks very similar to many web-based dynamic content generation technologies
such as Active Server Pages and Java Server Pages. Such technologies mix static
content with dynamically evaluated code blocks. XSLT mixes static content
with dynamically evaluated instructions. This was a conscious decision on the
part of the designers of XSLT.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<html>
<head><title>explicit stylesheet</title></head>
<body>
<h1>Hello: <xsl:value-of select='people/person/@name' /></h1>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

equivalent
<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xsl:version="1.0">
<head><title>literal result</title></head>
<body>
<h1>Hello: <xsl:value-of select='people/person/@name' /></h1>
</body>
</html>

Figure 15.5: Literal Result Elements

The input infoset shown in figure 15.3 contains several person elements but
the transform in figure 15.4 only emits content for the first such element; the

552 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

resulting infoset only contains the attribute values for the first person
element in the input infoset. This is because although each of the XPath
expressions selects a set of nodes, converting a node-set to a string returns the
text value of the first node in the set. Each person element could be
processed separately by using xsl:value-of instructions with XPath
expressions like people/person[1]/@name and
people/person[2]/@name. However, such an approach is unreasonable,
especially when the number of elements to be processed is not known in
advance. Fortunately, XSLT provides the xsl:for-each instruction for
processing sets of nodes. The instruction takes a select attribute whose value
is an XPath expression which, when evaluated, returns a node set. The content
of the xsl:for-each instruction is evaluated relative to each node in the
node set. Thus for a node-set with four nodes the xsl:for-each would be
evaluated four times and the relevant content emitted. Figure 15.6 shows a
transform that uses a xsl:for-each instruction. Given the input infoset
shown in figure 15.3, the output infoset would be as shown in figure 15.6.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<people>
<xsl:for-each select='people/person' >
<person>
<name><xsl:value-of select='@name' /></name>
<age><xsl:value-of select='@age' /></age>
</person>
</xsl:for-each>
</people>
</xsl:template> <?xml version="1.0" encoding="UTF-8"?>
</xsl:transform> <people>
<person><name>Martin</name><age>33</age></person>
<person><name>Hayley</name><age>30</age></person>
<person><name>Matthew</name><age>6</age></person>
<person><name>Samuel</name><age>4</age></person>
</people>

Figure 15.6: xsl:for-each example

It is worth noting that the xsl:for-each instruction changes the current


context. Any XSLT instructions, such as xsl:value-of, are always evaluated
relative to the current context. Inside an xsl:for-each the context is that of
the node-set that the select attribute evaluates to, rather than the context
of the enclosing XSLT instruction. In the example shown, the select attribute
of the xsl:for-each instruction is evaluated relative to the root of the
document while the select attribute of the 2 xsl:value-of instructions is
evaluated relative to the person element selected by each iteration of the
xsl:for-each.

Copyright © 2001, DevelopMentor Inc. 553


Module 15: XSLT

By default, the nodes selected by an xsl:for-each instruction are


processed in document order. Sometimes it is useful to be able to process the
nodes in a particular order so as to ensure that the output of a transform
appears in that order. The xsl:sort instruction, which appears as a child of
xsl:for-each can be used to achieve this. The select attribute of the
xsl:sort instruction determines what order the nodes will be processed in.
The value of the attribute is an XPath expression, evaluated relative to the
context selected by the xsl:for-each instruction, which determines which
values will be used to determine the sort order. For example, given the input
infoset shown in figure 15.3, the transform shown in figure 15.7 would produce
the output XML infoset shown in figure 15.7.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<people>
<xsl:for-each select='people/person' >
<xsl:sort select='@age' data-type='number'/>
<person>
<name><xsl:value-of select='@name' /></name>
<age><xsl:value-of select='@age' /></age>
</person>
</xsl:for-each>
</people>
<?xml version="1.0" encoding="UTF-8"?>
</xsl:template>
<people>
</xsl:transform>
<person><name>Samuel</name><age>4</age></person>
<person><name>Matthew</name><age>6</age></person>
<person><name>Hayley</name><age>30</age></person>
<person><name>Martin</name><age>33</age></person>
</people>

Figure 15.7: xsl:sort example

The select attribute of the xsl:sort instruction in the example specifies


that the value of the age attribute should be used to determine the order in
which the nodes are processed. Note that in the absence of schema
information, text in XML is just that, text. Therefore, the output would be
sorted according to the lexical order of the strings appearing in the age
attributes in the input infoset as shown below.

<?xml version="1.0" encoding="UTF-8" >


<people>
<person><name>Hayley</name><age>30</age></person>
<person><name>Martin</name><age>33</age></person>
<person><name>Samuel</name><age>4</age></person>

554 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

<person><name>Matthew</name><age>6</age></person>
</people>

Because the comparison is based on strings rather than numbers, 30 and 33


come before 4. Fortunately, XSLT provides other attributes to xsl:sort
including the data-type attribute. When the value of this attribute is number
(the default is text ) then the sort is performed by first converting the values
to numbers then doing the comparison.
Note that in both cases the resulting infoset is sorted in ascending order.
This can be reversed by setting the value of the order attribute to
descending (ascending is the default ). In addition sorting on multiple
fields can be achieved by specifying multiple xsl:sort instructions. The
node-set selected by the xsl:for-each instruction will initially be sorted
according to the values in the field specified by the first xsl:sort instruction.
If several nodes have the same value for that field, then the field identified by
the second xsl:sort instruction will be used to determine order within that
subset, and so on through any number of xsl:sort instructions.
In many transforms the decision about what to write to the output stream is
based on values in the input infoset. XSLT provides two constructs for dealing
with such decisions; xsl:if and xsl:choose. The former is a simple
conditional. If the condition is satisfied the content of the xsl:if element is
evaluated, otherwise the content is ignored, while the latter is very like a
switch statement in Java or C#. For xsl:if the condition is specified in a
test attribute whose value is an XPath expression that evaluates to a boolean.
Figure 15.8 shows a transform with a conditional statement. Given the input
infoset shown in figure 15.3 the output infoset would be as shown in figure
15.8. Note that the test attribute is evaluated relative to the current context,
which in this case is each person element in turn from the node-set selected
by the xsl:for-each instruction. Because the comparison expression
contains a greater-than operator the comparison is numerical rather than
lexical.

Copyright © 2001, DevelopMentor Inc. 555


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<people>
<xsl:for-each select='people/person' >
<xsl:if test='@age > 18' >
<adult><xsl:value-of select='@name' /></adult>
</xsl:if>
</xsl:for-each>
</people>
</xsl:template>
</xsl:transform>
<?xml version="1.0" encoding="UTF-8"?>
<people>
<adult>Martin</adult>
<adult>Hayley</adult>
</people>

Figure 15.8: xsl:if example

Dealing with multiple conditions can be done with multiple xsl:if


instructions. Alternatively the xsl:choose construct can be used. This
instruction has one or more xsl:when child elements, each having a test
attribute whose value, as with xsl:if is an XPath expression that evaluates to
a boolean. The content of the first xsl:when instruction whose test attribute
evaluates to true is evaluated. All other xsl:when instructions are skipped.
The xsl:choose instruction can also have an optional xsl:otherwise child
element that acts as a default clause, which will be evaluated if none of the
test attributes on the xsl:when instructions evaluate to true. If it appears,
an xsl:otherwise instruction must appear after all xsl:when instructions.
Figure 15.9 shows a transform with an xsl:choose instruction. Given the
input infoset shown in figure 15.3, the output infoset would be as shown in
figure 15.9.

556 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<people>
<xsl:for-each select='people/person' >
<xsl:choose>
<xsl:when test='@age > 18' >
<adult><xsl:value-of select='@name' /></adult>
</xsl:when>
<xsl:otherwise>
<child><xsl:value-of select='@name' /></child>
</xsl:otherwise>
</xsl:choose> <?xml version="1.0" encoding="UTF-8"?>
</xsl:for-each> <people>
</people> <adult>Martin</adult>
</xsl:template> <adult>Hayley</adult>
</xsl:transform> <child>Matthew</child>
<child>Samuel</child>
</people>

Figure 15.9: xsl:choose example

Many transformations must generate dynamic element/attribute names or must


compute some text that is assigned to an attribute in the result tree. The
xsl:element instruction dynamically generates elements with the specified
name and namespace URI and the xsl:attribute instruction dynamically
generates attributes with a name, namespace URI, and content value. Figure
15.10 shows a transform with xsl:element and xsl:attribute
instructions. Given the input infoset shown in figure 15.3 the output infoset
would be as shown in figure 15.10. These are especially useful if you want to
write a transform that generates a transform as they are one way to emit XSL
instructions into the output infoset without them being interpreted/executed
by the XSL processor.

Copyright © 2001, DevelopMentor Inc. 557


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' > Attribute
<xsl:template match='/' > value
<person> template
<xsl:element name=‘{people/person/@name}’>
<xsl:attribute name=‘age’>
<xsl:value-of select='people/person/@age' />
</xsl:attribute>
</xsl:element>
</person>
</xsl:template>
</xsl:transform> <?xml version="1.0" encoding="UTF-8"?>
<person>
<Martin age=‘33’</Martin>
</person>

Figure 15.10: xsl:element and xsl:attribute example

Notice the use of the attribute value template. This is an inline expression that
is evaluated within an attribute declaration. Attribute value template
expressions are enclosed in {} and can contain arbitrary XPath expressions and
can also contain variable ($variable) references (more on these later).

558 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

XSLT syntax (2)


Working with multiple templates

• Calling named templates


• Applying templates rules
• Variables
• Parameters
• Copying node-sets
• Identity transform

560 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

Up until now, we have only considered single template XSLT transforms. More
complex transforms can benefit from partitioning functionality into additional
templates, a "divide and conquer" approach where individual templates apply a
simple transformation. This is much like you might subdivide a Java program
into multiple classes with multiple methods. All such templates are to-level
children of the xsl:stylesheet (or xsl:transform) element.
A template can be given a symbolic name and can be invoked using that
name. A template is named by giving it a name attribute. In this sense it is the
moral equivalent of a function in any procedural programming language. Figure
15.11 shows how to define a named template and how to invoke it by name
with the xsl:call-template instruction. Invoking a named template passes
the current XSLT context to the named template.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<people>
<xsl:call-template name=‘outputpeople’/>
</people>
</xsl:template>

<xsl:template name=‘outputpeople’>
<xsl:for-each select='people/person' >
<person><xsl:value-of select='@name' /></person>
</xsl:for-each>
<?xml version="1.0" encoding="UTF-8"?>
</xsl:template>
<people>
</xsl:transform>
<person>Martin</person>
<person>Hayley</person>
<person>Matthew</person>
<person>Samuel</person>
</people>

Figure 15.11: xsl:call-template example

It is possible to parameterize a call. Parameters are declared within body of


template and passed using the xsl:with-param instruction as shown in figure
15.12. XSLT transforms can also be parameterized. They are passed in an XSLT-
processor dependent fashion. XSLT transform parameters are declared at
xsl:stylesheet scope using the xsl:param instruction. Default values can
be assigned to parameters in case they are not passed to the transform. Figure
15.13 illustrates how to use a transform parameter and shows how to run a
transform and pass it a parameter if you are using Xalan. Figure 15.14
illustrates how run a parameterized transform from Java code.

Copyright © 2001, DevelopMentor Inc. 561


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<people>
<xsl:call-template name='outputagedpeople'>
<xsl:with-param name='numyears'>18</xsl:with-param>
</xsl:call-template>
</people>
</xsl:template>
<xsl:template name='outputagedpeople'>
<xsl:param name='numyears' />
<xsl:for-each select='people/person' >
<xsl:if test='@age > $numyears' >
<person><xsl:value-of select='@name' /></person>
</xsl:if>
<?xml version="1.0" encoding="UTF-8"?>
</xsl:for-each>
<people>
</xsl:template>
<person>Martin</person>
</xsl:transform>
<person>Hayley</person>
</people>

Figure 15.12: xsl:with-param example

java org.apache.xalan.xslt.Process -IN input.xml -XSL param.xsl


-PARAM numyears 32

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:param name='numyears'>18<xsl:param>
<xsl:template match='/' >
<people>
<xsl:call-template name='outputagedpeople‘/>
</people>
</xsl:template>
<xsl:template name='outputagedpeople'>
<xsl:for-each select='people/person' >
<xsl:variable name=‘moniker’ select=‘@name’ />
<xsl:if test='@age > number($numyears‘) >
<person><xsl:value-of select=‘$moniker' /></person>
</xsl:if> <?xml version="1.0" encoding="UTF-8"?>
</xsl:for-each>
<people>
</xsl:template>
</xsl:transform> <person>Martin</person>
</people>

Figure 15.13: xsl:param example

562 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

import javax.xml.transform.*;
import javax.xml.transform.stream.*;
...
public void process(String src, String xsl,
String dest, Dictionary arguments) {
try {
TransformerFactory tf =
TransformerFactory.newInstance();
Transformer t =
tf.newTransformer(new StreamSource(xsl));
if (arguments!=null) {
Enumeration keys = arguments.keys();
Enumeration values = arguments.elements();
while(keys.hasMoreElements()) {
String key = (String)keys.nextElement();
String value = (String)values.nextElement();
transformer.setParameter( key, value);
}
transformer.transform(new StreamSource(src),
new StreamResult(dest));
} catch (Exception e) {
e.printStackTrace();
}
}
Figure 15.14: Running a parameterized transform programmatically

XSLT also permits the use of named constants in programs using the
xsl:variable instruction. The content of the xsl:variable instruction can
contain XSLT instructions that are used to compute its value. Alternatively, its
select attribute can be used to initialize it. If a variable is define locally
within a template (or a xsl:for-each) then it is scoped by the template (or
xsl:for-each). Such a "local" variable is re-initialised each time the
template is invoked (or for each iteration of the xsl:for-each loop). A
variable defined as a child of xsl:transform or xsl:stylesheet is "global"
to the transform and is initialized once. Once a variable has been assigned a
value within its scope it cannot be re-assigned another one. It is really a
constant. A Figure 15.13 also illustrates the use of variables.
Templates can also be invoked using pattern matching where the XSLT
processor chooses which template to run. Patterns are associated with a
template using its match attribute whose value is defined using a limited form
of XPath (only the child and attribute axes are allowed as well as //). The
binding of a pattern to a template is referred to as a "template rule". The XSLT
processor will invoke a template rule whenever its associated pattern is
matched within the input XML infoset. In the case that there are multiple
templates that match a pattern, the XSLT specification defines a scheme to

Copyright © 2001, DevelopMentor Inc. 563


Module 15: XSLT

decide which one will be picked. The execution of a template rule based on its
associated pattern is often referred to as "applying a template rule".
We have already seen that the XSLT processor always starts a transform by
invoking the template rule that matches the document root of the input XML
infoset. Subsequently, the xsl:apply-templates instruction is used as the
trigger to invoke further template rules. The xsl:apply-templates
instruction is similar to the xsl:for-each instruction in that it takes a node-
set identified by its select attribute and iteratively applies a template to
each node in some order, changing the context node for each iteration.
However, the difference is that xsl:apply-templates chooses the template
rule to apply to each node based on pattern-matching the node against all
known template rules. Figure 15.15 illustrates how this works. The XSLT
processor begins processing by invoking the template rule that matches the
document root of the input XML infoset. This template emits the people
element and then calls xsl:apply-templates. If the select attribute is
missing, then this is the same as supplying a select attribute of . (or
node()). This is where you might expect that the template processing gets
recursive pretty quickly! However, XSLT defines a built-in template rule for
every node-type. These rules have the lowest possible precedence and will only
be selected if there is no other match. The built-in template rule for the
document root node and for an element node calls apply-templates on its
children. So, the built-in template rule for the document root applies the best
match template rule to each of its children (the people element). There is no
template rule that matches the people element but there is a built-in
template rule for the element node. It applies the best match template rule to
each of its children. There is a template rule that matches the person
element and is invoked four times, once for each person element child of the
people element.

564 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<people>
<!-- implicitly a select attribute of '.' -->
<xsl:apply-templates />
</people>
</xsl:template>
<xsl:template match='person'>
<xsl:for-each select='.' >
<person><xsl:value-of select='@name' /></person>
</xsl:for-each>
<?xml version="1.0" encoding="UTF-8"?>
</xsl:template>
<people>
</xsl:transform>
<person>Martin</person>
<person>Hayley</person>
<person>Matthew</person>
<person>Samuel</person>
</people>

Figure 15.15: xsl:apply-templates example

This form of programming is often called declarative template programming


and comes into its own when dealing with an irregular input document where
the source nodes are not in well-defined locations. Consider figure 15.16 and
how easy it would be to converts noun elements to b elements by using
pattern-matching even though we cannot predict where the noun elements are
going to be. Figure 15.17 illustrates.
<book>
<chapter>
<title>Testing your <noun>typewriter</noun></title>
<p>The quick brown <noun>fox</noun> jumped over
the lazy <noun>dog</noun></p>
</chapter>
</book> book

chapter

title p

text noun text noun text noun

Figure 15.16: irregular input

Copyright © 2001, DevelopMentor Inc. 565


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match="noun">
<b><xsl:value-of select="."/></b>
</xsl:template>

<xsl:template match="/">
<html>
<body>
<p><xsl:apply-templates/></p>
</body>
</html> <html>
</xsl:template> <body>
</xsl:transform> <p>Testing your <b>typewriter</b>
The quick brown <b>fox</b> jumped over
the lazy <b>dog</b></p>
</body>
</html>

Figure 15.17: DTP and irregular input

XML to XML transformations typically involve copying nodes from the source
infoset to the result tree. The xsl:copy instruction doesn't evaluate an
expression but, rather, takes the current context node and copies it directly
into the result tree. This does not copy attributes or child nodes! It is possible
to use apply-templates to copy child nodes as the default template rule for
text() nodes will handle recursive text node copying. Alternatively, the
xsl:copy-of instruction takes the node set identified by its select attribute
(whose value is an XPath expression) and copies it directly into the result tree.
Figure 15.18 shows a common use for the xsl:copy instruction where the
input infoset must be written directly back to the output infoset as is, except
for certain patterns. The top transform is known as an identity transform.

566 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<!-- This is the identity transform -->
<xsl:template match=‘@*|node()’>
<xsl:copy>
<xsl:apply-templates select=‘@*|node()’/>
</xsl:copy>
</xsl:template>
<!-- This transform overrides selected items -->
<xsl:template match=‘@age’>
<age><xsl:value-of select=‘.’ /></age>
</xsl:template>
<?xml version="1.0" encoding="UTF-8"?>
</xsl:transform>
<people>
<person name=‘Martin’><age>33</age></person>
<person name=‘Hayley’><age>30</age></person>
<person name=‘Matthew’><age>6</age></person>
<person name=‘Samuel’><age>4</age></person>
</people>

Figure 15.18: xsl:copy example--identity transform

Copyright © 2001, DevelopMentor Inc. 567


Module 15: XSLT

XSLT syntax (3)


Controlling output

• Static text in transform written to result tree


• xsl:text also emits text
• By default transform output is XML
• Processor may apply heuristics and output HTML
• xsl:outputmethod attribute may be xml, html or text
• Output escaping of built-in entities depends on output method
• disable-output-escaping attribute of xsl:value-of and xsl:text
affects this
• Whitespace-only nodes are stripped from transform
• Whitespace-only nodes are not stripped from input by default
• xsl:preserve-space/xsl:skip-space instructions and xml:space
attribute affect this

568 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

In the absence of any other information, XSLT processors usually assume that
the output stream is going to be XML. The XSLT specification defines a list of
heuristics that will be used to figure out whether the output is, in fact, HTML.
The xsl:output instruction tells the XSLT processor to emit different types of
output. Its most interesting attribute is method that can be "xml" or "html" or
"text". If the method is "html" or "text" or if the XSLT processor figures out that
the output is HTML, then there is no xml declaration and no expectation of
well-formedness.
The method attribute of xsl:output controls the handling of the built-in
entities, lt, gt, amp, apos and quot. In "text" mode they are output in their
literal values. In the other modes they are emitted as entity references. The
latter behaviour can be disable for output generated with the xsl:value-of
and xsl:text instructions by setting their disable-output-escaping
attribute to "yes". Static content within an XSLT program is automatically
written to text nodes in the result tree but static content can also be explicitly
generated as text nodes in the result tree using the xsl:text instruction.
Considering the XML input infoset defined by figure 15.19, then figure 15.20
shows how the output escaping works if the result tree is XML and figure 15.21
shows the difference when the xsl:output instruction is used to change the
result tree to text.

<?xml version="1.0" encoding="UTF-8"?>


<people>
<person>
<name>Martin</name>
<age>32 &amp; 1</age>
</person>
<person>
<name>Hayley</name>
<age>30</age>
</person>
</people>
Figure 15.19: Consider a different input XML infoset...

Copyright © 2001, DevelopMentor Inc. 569


Module 15: XSLT

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:template match='/' >
<person>
<age1><xsl:value-of select='people/person/age' /></age1>
<age2><xsl:value-of disable-output-escaping='yes'
select='people/person/age' /></age2>
<message>
<xsl:text disable-output-escaping='yes'>&amp; relax,</xsl:text>
<xsl:text>&amp; relax,</xsl:text>
&amp; relax
</message>
</person > <?xml version="1.0" encoding="UTF-8"?>
</xsl:template> <person>
</xsl:transform> <age1>33 &amp; 1</age1>
<age2>33 & 1</age2>
<message>& relax,&amp; relax, &amp; relax</message>
</person>

Figure 15.20: Output escaping for XML output

<?xml version="1.0" encoding="UTF-8"?>


<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:output method=‘text' />
<xsl:template match='/' >
<person>
<age1><xsl:value-of select='people/person/age' /></age1>
<age2><xsl:value-of disable-output-escaping='yes'
select='people/person/age' /></age2>
<message>
<xsl:text disable-output-escaping='yes'>&amp; relax,</xsl:text>
<xsl:text>&amp; relax,</xsl:text>
&amp; relax
</message>
</person >
</xsl:template>
</xsl:transform>

33 & 133 & 1& relax,& relax, & relax

Figure 15.21: Output escaping for text output

Up until this point we have been economical with the truth about whitespace.
All of our result tree examples have been nicely formatted to fit the space and
didn't represent the truth of whitespace processing. Here is the truth! The
truthWhitespace-only nodes in an XSL transform are not considered significant
and so are stripped and do not appear in the output result tree. However, the
xsl:text instruction can be used to explicitly output whitespace.
Whitespace-only nodes in the input XML infoset are preserved unless the
xsl:strip-space instruction is used. This instructs the XSL processor to strip
child whitespace-only nodes from the input infoset for a given list of elements
specified in its elements attribute. If a xsl:strip-space is in effect for an

570 Copyright © 2001, DevelopMentor Inc.


Module 15: XSLT

element, a xsl:preserve-space in effect for any of that element's child


elements will override and preserve the child element's child whitespace-only
nodes. If an element in the input XML infoset has an associated xml:space
attribute the xsl:strip-space attribute has no effect. Figure 15.22 shows
the effect of the xsl:strip-space and xsl:preserve-space instructions.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0' >
<xsl:strip-space elements='people' />
<xsl:preserve-space elements='person' />
<xsl:template match='/' >
<xsl:copy-of select='.' />
</xsl:template>
</xsl:transform>

<?xml version="1.0" encoding="UTF-8"?>


<people><person>
<name>Martin</name>
<age>32 &amp; 1</age>
</person><person>
<name>Hayley</name>
<age>30</age>
</person></people>

Figure 15.22: Whitespace-only nodes in the input XML infoset

Copyright © 2001, DevelopMentor Inc. 571


Module 15: XSLT

Summary
• XSLT is a declarative language for transforming XML
• Transform consist of one or more templates
• Template consists of both static and dynamic content
• Traditional programming constructs, like looping and conditionals,
supported
• Templates may be used in a procedural or declarative fashion
• Templates (and the entire transform) can be parameterized
• apply-templates controls the flow of execution in DTP

572 Copyright © 2001, DevelopMentor Inc.


Module 16

Platform Security

Copyright © 2001, DevelopMentor Inc. 573


After completing this module, you should be able to:
 Understand how the SecurityManager works
 Activate and configure Java 2 security
 Create custom Permissions
 Know when to use privileged scopes

574 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

Platform Security
The Java virtual machine protects all sensitive
operations through a flexible security manager.

Copyright © 2001, DevelopMentor Inc. 575


Module 16: Platform Security

SecurityManager
The SecurityManager checks sensitive operations

• Originally an abstract base class


• Since Java 2, delegates to AccessController
• Most server processes should activate security

576 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

The SecurityManager acts as a chokepoint for sensitive operations. Java


APIs that access files, the network, printers, class loaders, system properties,
reflection, and other sensitive parts of the platform must pass a
SecurityManager check. If the caller is not trusted, the SecurityManager
will throw a SecurityException, as shown in Figure 16.1.
class EvilClass {
FileOutputStream fos =
new FileOutputStream("/system.dat");
//...

SecurityManager File
System

class GoodClass {
FileOutputStream fos =
new FileOutputStream("candy.bar");
//...

Figure 16.1: The SecurityManager Intercepts Calls to Protected Resources

Prior to the release of Java 2, the SecurityManager was an abstract base


class. Applications that wanted security had to write their own concrete
subclasses, which was tedious and error-prone. Java 2 includes a concrete
SecurityManager, which delegates to a new class called AccessController.
AccessController implements the core functionality in a way that is
suitable for most applications.
Java 2 security is off by default. In general, server processes should turn
Java security on, either via a command line switch of by calling
System.setSecurityManager. Both options are shown in Figure 16.2. An
active security system prevents attacks, but it also forces you to think carefully
about the needs of each subsystem in your application. Sometimes the very act
of turning on security can reveal design flaws and hidden dependencies in an
application.
>java -Djava.security.manager [AppToRunSecurely]

* OR *

public static void main(String[] args) {


System.setSecurityManager(new SecurityManager());
//etc.
}
Figure 16.2: Turning on the SecurityManager

Copyright © 2001, DevelopMentor Inc. 577


Module 16: Platform Security

Call Stack and Code Source


SM checks code source for each class on call stack

• All classes must pass check


• CodeSource is URL plus signers
• SecureClassLoader assigns CodeSource
• Class.getProtectionDomain returns CodeSource

578 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

In order for a call to pass a security check, all of the classes on the call stack
must be trusted. (Trying to guess which levels of the stack to check would be
tedious and error prone.) SecurityManager implements a protected method
getClassContext that returns an array of the classes on the call stack,
ordered from the immediate caller back to the top. Figure 16.3 shows
psuedocode for checking each class on the stack. You should never have to
write code like this; it is already built into SecurityManager.
public class MySM extends SecurityManager {
public void checkRead(String fileName) {
Class[] classes = getClassContext();
for (int n=0; n < classes.length; n++) {
if (!permittedToRead(classes[n], fileName) {
throw new SecurityException("Shame on you");
}
}
}
}
Figure 16.3: Checking All Classes on the Stack

With a custom SecurityManager, you could evaluate the call stack based on
any criteria you chose. However, the entire Java 2 security model is build
around the standard SecurityManager, which evaluates classes based on
their java.security.CodeSource. The CodeSource for a class is the URL
the class came from, plus the digital signers of the class, if any.
Class loaders are critical to Java 2 security, because they are responsible for
assigning the CodeSource. The SecureClassLoader class calls a special
version of defineClass that takes an extra
java.security.ProtectionDomain argument. ProtectionDomain
contains a class's code CodeSource plus the granted permissions.
URLClassLoader extends SecureClassLoader, so most Java classes get
their CodeSource set correctly. Figure 16.4 shows setting and retrieving the
CodeSource
//SecureClassLoader calls this method of ClassLoader
protected final Class defineClass(
String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain);

//You can discover the results:


public void printCodeSource(Class cls) {
System.out.println(
cls.getProtectionDomain().getCodeSource();
}
Figure 16.4: Setting and Retrieving the CodeSource

Copyright © 2001, DevelopMentor Inc. 579


Module 16: Platform Security

Policy
The system policy assigns permissions to code sources

• Abstract Policy class


• Reference implementation configured by policy files
• Grant blocks are additive

580 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

In order to associate permissions with a code source, SecureClassLoader


consults the system policy. The reference implementation of the system policy
uses a text file called the policy file to associate permissions with a code
source. Figure 16.5 shows an example policy file.
grant {
permission java.net.SocketPermission "*:1024-", "accept,
connect";
permission java.io.FilePermission "${/}shared${/}-",
"read";
};
Figure 16.5: Sample Policy File

Granting permissions is an additive process; there is no way to subtractively


define permissions (e.g. read access to every file except secrets.txt). If a grant
block in a policy file does not specify a codeSource or signedBy entry, then that
grant block applies to all code sources or all signers, respectively.
The entire path through the security architecture, from granting a
permission in the policy file to checking the permission at runtime, is shown in
Figure 16.6. The left side of the figure shows the work that is done before a
class is loaded, to cache its protection domain. The right side shows how the
access controller uses the cached information to check each class on the call
stack.

Copyright © 2001, DevelopMentor Inc. 581


Module 16: Platform Security

Policy AccessController
checkPermission(p)

grant ---- {
---; 1. get array of
---; classes on call
3. get array of permissions
}; stack with SM's
from the protection domain
getCallContext

implies?
Policy object p
implies?
codesource permissions p
implies?
p
implies?
p

2. get array of code sources 4. permit the call if every


SecureClassLoader with class's set of permissions
caches codesource to getProtectionDomain implies p
permissions mapping in a
ProtectionDomain

Figure 16.6: From the Policy File to the AccessController

Internally, the policy is represented by the java.security.Policy class,


which is an abstract base class. The file-based implementation can be replaced
by implementing a new concrete subclass of Policy.

582 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

Default Policy
Located in JRE/lib/security/java.policy

• Very restrictive
• Must be activated
• Settings can be augmented or replaced

584 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

The default policy is taken from files listed in JRE/lib/security/java.security.


The default, which is rarely changed, is shown in Figure 16.7. The default
policy is very restrictive, disallowing most secured operations. You can
augment the default policy, or replace it altogether, by setting various
command line properties. Figure 16.7 shows some examples.
rem "=" adds my.policy in addition to default policy
java -Djava.security.manager
-Djava.security.policy=my.policy
SomeApp

rem "==" replaces default policy with my.policy


java -Djava.security.manager
-Djava.security.policy==my.policy
SomeApp
Figure 16.7: Choosing the Policy from the Command Line

Copyright © 2001, DevelopMentor Inc. 585


Module 16: Platform Security

Permissions
The permissions listed in the Policy are Java classes

• Represent secured operation


• Name + action + target
• Easy to add custom permissions

586 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

The permissions listed in the Java policy file also have a Java class
representation, as subclasses of java.security.Permission. Permission
has a constructor that takes a single argument, which is the target of the
permission. While a permission represents a category, the target represents a
specific instance. So, the target for a java.io.FilePermission is the
actual file name. Some permissions also define a list of actions, initialized by a
second String argument in the specific permission's constructor. For example,
FilePermission's actions are read, write, execute, and delete.
Many permissions use the hierarchical property naming convention for target
names, e.g. target.subTarget.subsubTarget. However, the format of target
names is left to the discretion of a permission's implementer, so consult your
documentation.
It would be tedious to specify permissions by listing every combination of
target and action. Therefore, permission classes often define wildcards that
can be used in place of a specific target or action. The architecture does not
mandate a standard naming convention for wildcards, so you must check the
documentation for a particular permission to discover the wildcards that it
supports. Some common wildcards are listed in Figure 16.8.
Permission Wildcard Meaning
FilePermission all files in current directory
*
FilePermission - all files in current and subdirectories
FilePermission <<ALL FILES>> all files
PropertyPermission any value at current level in hierarchy
*
RuntimePermission any value at current level in hierarchy
*
SocketPermission any value in left of DNS, e.g. *.sun.com
*
SocketPermission -, #-, #-# range of port numbers

Figure 16.8: Wildcards in the Standard Permissions

It is straightforward to create custom permissions. Simply subclass


Permission. Then define a (String) constructor if the permission has
targets only, or a (String, String) constructor if the permission has
targets and actions. The policy file reader will automatically discover and
access custom permissions using Reflection. Figure 16.9 demonstrates the
source code and policy file syntax for a custom permission.

Copyright © 2001, DevelopMentor Inc. 587


Module 16: Platform Security

/*
grant {
permission WarpPermission "maxWarp", "9";
};
*/
public final class WarpPermission extends Permission {
private int warpFactor;
public WarpPermission(String name, int warpFactor) {
super(name);
if (!name.equals("maxWarp")) {
throw new IllegalArgumentException("invalid: "
+ name);
}
this.warpFactor = warpFactor;
}
public WarpPermission(String action, String warpFactor)
{
this(action, Integer.parseInt(warpFactor));
}
public boolean implies (Permission p) {
//instanceof ok since WarpPermission is final
if (!(p instanceof WarpPermission))
return false;
WarpPermission other = (WarpPermission) p;
return (warpFactor > other.warpFactor);
}
//etc.
Figure 16.9: Defining a Custom Permission

In order to process wildcards correctly, permissions must also implement


implication. A wildcard permission implies the specific permissions that
correspond to the wildcard. Figure 16.9 shows a simple example of implication.
The special permission java.security.AllPermission implies all other
permissions.

588 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

Privileged Scopes
Privileged scopes customize how stacks are checked

• Checking entire stack expensive


• Some operations should succeed regardless of stack
• Define scope with PrivilegedAction subclass

590 Copyright © 2001, DevelopMentor Inc.


Module 16: Platform Security

In some situations, applying a security checking to the entire call stack is


inappropriate. Consider an Auditor class that logs all security-related
exceptions to a file. If malicious code triggers a security exception, then the
malicious code will still be on the call stack when Auditor tries to write the
file. Auditor needs some way to say "Permit this operation based on my
credentials alone. Do not check any higher up the stack."
Privileged scopes provide this ability. To implement a privileged scope,
create a subclass of java.security.PrivilegedAction. Then pass an
instance of the subclass to AccessController.doPrivileged(). The
AccessController will execute the privileged action's run method without
checking back up the call stack. Figure 16.10demonstrates using a privileged
action to log to the file system.
try {
AccessController.doPrivileged(new
PrivilegedExceptionAction() {
public Object run() throws ClassNotFoundException {
FileOutputStream fos = new FileOutputStream(file);
//write something to the file
}
});
} catch (java.security.PrivilegedActionException pae) {
throw (IOException) pae.getException();
}
Figure 16.10: Using a PrivilegedAction

Copyright © 2001, DevelopMentor Inc. 591


Module 16: Platform Security

Summary
• SecurityManager checks sensitive operations
• Checks based on call stack and code source
• Policy conveys permissions to classes
• Permissions describe secured operations
• Privileged scopes control stack checking

592 Copyright © 2001, DevelopMentor Inc.


Module 17

Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 593


Authentic and secure communication on the web

After completing this module, you should be able to:


 think about the needs of distributed security
 explore the HTTP(S) security mechanisms
 understand the declarative security model of Servlets
 appreciate the options for programming security when necessary

594 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

Introduction to Distributed Security


Application security in Java has traditionally been
based on code origin. Distributed systems also
require secure communications based on
authenticating either or both parties to a
conversation.

Copyright © 2001, DevelopMentor Inc. 595


Module 17: Java Distributed Security

The needs of distributed security


What is security based on?

• In Java it's code origin


• Acceptable when code is mobile
• Distributed security based on who is trying to run the code
• Must authenticate calling principal
• May need mutual authentication
• Credentials are proof of identity
• Some authority verifies credentials
• Acceptable when request is mobile

596 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

One of the features of Java is how easily code can be downloaded and
composed into a running application. However, such code has the potential to
execute critical operations that manipulate sensitive system data, so it is
imperative to distinguish code that can be trusted from code that cannot. To
this end, the Java security model is based on the origin of the running code.
Sensitive operations are allowed or disallowed based on where the classes in
the current call stack were loaded from and/or who signed them.
In a distributed system, code representing business operations is hosted on
one or more servers. A client request acts as a trigger to execute server code
that has the potential to perform critical operations that manipulate sensitive
system data. It is important to distinguish requests that can be trusted from
those that cannot. The server must enforce security based on who is
attempting to run the code, and that means being able to verify the identity of
the caller.
It gets more complicated when client and server communicate over a public
network where servers may be more easily spoofed. The client may also want
some guarantee that the server is genuine before accepting or providing
certain information. There are questions to be answered. How can the system
tell which clients can be trusted? How is it possible to specify which clients can
access which functionality? How can the clients tell which servers can be
trusted? How can malicious persons be stopped from accessing the system or
tampering with requests and responses? How can sensitive data be hidden from
prying eyes?
A distributed system is typically made up of code executing on behalf of
different principals where a principal is some uniquely identified participant in
the system, and could be a machine or a person. For instance, client code
running on behalf of "Alice" may want to communicate with server code running
on behalf of "Bob". Different principals within the system will have different
authorization levels so the server needs to know which principal is making a
request before proceeding. The server asks the client to supply some
credentials for the calling principal as proof of their identity. The credentials
are something only the calling principal (Alice in this example) could know or
have and which must be verifiable by some authority. For example, a user
name/password pair or something more exotic like a retinal scan or a hand
geometry test. The authority is trusted by both parties to corroborate the
validity of the credentials and may be something like a domain controller or a
certificate authority. The process of checking credentials is called
authentication. When the client and server authenticate each other it is called
mutual authentication.
To see how authentication takes place over the web the next section looks
at the main HTTP authentication techniques.

Copyright © 2001, DevelopMentor Inc. 597


Module 17: Java Distributed Security

HTTP authentication mechanisms


One built-in mechanism, two built-in schemes

• Challenge/response establishes both parties know secret


• Server challenge: 401 + WWW-Authenticate headers
• Client chooses strongest scheme it understands
• Basic Authentication: Base-64 encoded username/password
• Only safe over secure channel
• Digest Authentication: Password hashed
• Safer but not designed for secure transactions

598 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

HTTP defines a simple challenge/response authentication mechanism that


supports two built-in authentication schemes--Basic Authentication and Digest
Authentication--each of which verifies that both parties in an exchange know a
shared secret password. To illustrate the challenge/response mechanism let's
look at the simpler of the two authentication schemes, Basic Authentication.
Authentication is needed if the caller attempts to access a secured resource,
perhaps by sending an HTTP request to the server as shown in figure 17.1.
GET /secureApp/resource1 HTTP/1.1
Host: foo
Figure 17.1: A client HTTP request

The server sends back a challenge to the caller to authenticate. This takes the
form of a "401 Unauthorized" response with a "WWW-Authenticate" header as
shown in figure 17.2.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="homer"
Figure 17.2: The server challenge for Basic Authentication

The "WWW-Authenticate" header contains the name of the authentication


scheme ("Basic") and the security realm ("homer"). The security realm
determines what set of credentials the caller should use. The caller's response
is to resubmit the request along with an additional "Authorization" header
whose value contains the scheme ("Basic"), the realm ("homer") and the
credentials. The credentials are simply a user name and password that have
been base-64-encoded. Figure 17.3 illustrates.
GET /secureApp/resource1 HTTP/1.1
Host: foo
Authorization: Basic ZnJlZDp0b21jYXQ=
Figure 17.3: The client resubmits the HTTP request with Basic
Authentication credentials

If the server can verify the supplied credentials to authenticate the caller
within the associated realm then resource access is allowed assuming the caller
has authorization. If authentication fails the server sends back a "401
Unauthorized" response again. An authorization check determines whether the
authenticated caller is allowed access to the resource. If access is not allowed
the server sends back a "403 Access denied" response.
Basic Authentication is too limited. HTTP is a stateless protocol so
authentication information must be included with every client request for a
secured resource. Once authenticated, the caller could cache the credentials
for a given subset of server resources (for all resources that share the same
URL base perhaps) and reissue those credentials, unprompted, with subsequent
requests. However this opens up the possibility of replay attacks. In a replay

Copyright © 2001, DevelopMentor Inc. 599


Module 17: Java Distributed Security

attack, a valid request is repeatedly re-sent to the server by a malicious


person. This is bad if the request represents an operation such as "transfer $100
from account A to account B". Also, base-64 encoding is not encryption and is
completely reversible by anyone. This means that the user name/password pair
is being sent as plaintext and so a malicious snooper could gain access to any
other resource protected by the same user name/password pair. It also means
that a malicious server could spoof a service in order to gain a password. For
these reasons it only makes sense to use Basic Authentication over an
encrypted link and with strong server authentication. Remember also, the
server gets to see your clear text password and of course you may not want this
to happen. Enter Digest Authentication.
Digest Authentication was introduced in HTTP 1.1 and is designed to improve
on Basic Authentication by allowing the client to prove knowledge of a
password without transmitting it on the wire and to provide more safeguards
against replay attacks. The challenge/response mechanism works in a similar
way to Basic Authentication but the details of the challenge and response are
different. This time the server's challenge looks something like figure 17.4.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest realm="homer",
qop="auth",

nonce="5fef9f6239b0526151d6eebd12196cdc",

opaque="c8202b69f571bdf3ece44c4ce6ee2466"
Figure 17.4: The server challenge for Digest Authentication

The "WWW-Authenticate" header contains the name of the authentication


scheme ("Digest") and the realm ("homer") as before, but Digest Authentication
requires other parameters to authenticate and these are also included in the
header. The most interesting parameter is the "nonce" which stands for number
once. The nonce is a value meaningful to the server that is valid only for the
current authentication. The client takes the user name, password, realm,
nonce, HTTP method and request uri and calculates a digest from them. A
digest is a fixed-length encoding of some data. It has the properties that the
data cannot be deduced from the digest and that two digests are identical for
the same data. The default digest algorithm used is MD5, although others can
be specified. The caller then resubmits the HTTP request as in figure 17.5 with
an "Authorization" header whose response parameter is the calculated digest.
Notice that the client never sends the password on the wire as only the digest
is transmitted.

600 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

GET /secureApp/resource1 HTTP/1.1


Host: foo
Authorization: Digest username="fred",
realm="homer",
qop="auth",

nonce="5fef9f6239b0526151d6eebd12196cdc",

opaque="c8202b69f571bdf3ece44c4ce6ee2466",

response="5773a30ebe9e6ce90bcb5a535b4dc417"
Figure 17.5: The client resubmits the HTTP request with Digest
Authentication credentials

The server creates a message digest from the same data used by the client (the
server has the user's password) and then compares the two. If they are the
same then the credentials are valid and, subject to an authorization check, the
caller is allowed access to the requested resource. If authentication fails then
the server sends back a "401 Unauthorized" error and if authorization fails then
the server sends back a "403 Access Denied" error.
Because the password is never sent in the clear this is much safer than Basic
Authentication but it isn't perfect. The server must hold each user's password in
a form suitable for calculating the MD5 digest. These passwords must be stored
securely as anyone possessing them could masquerade as any valid user.
Depending on the server's choice of nonce Digest Authentication is potentially
open to replay attacks. One recommended approach is for the server to
compose the nonce from a hash of the resource URL, the caller's IP address, a
time stamp, and a private key known only to the server. This way the server
can guard against replay attacks by restricting the reuse of a nonce to the
specified resource, requested from the specified the IP address and limited to
the period of the nonce's validity. That would probably be safe enough for
HTTP GETs but to completely prevent replay attacks against non-idempotent
operations requested by HTTP POSTs the server would need to refuse to accept
a nonce it had seen before. Given that the HTTP protocol is stateless, this is
more work for the server. Generally, the safer the nonce the greater the load
on the server and the more re-authentication is required by the caller.
Either Basic Authentication or Digest Authentication may be acceptable to a
server when securing a resource, in which case the server can send a challenge
with multiple "WWW-Authenticate" headers as in figure 17.6.

Copyright © 2001, DevelopMentor Inc. 601


Module 17: Java Distributed Security

HTTP/1.1 401 Unauthorized


WWW-Authenticate: Basic realm="homer"
WWW-Authenticate: Digest realm="homer",
qop="auth",

nonce="5fef9f6239b0526151d6eebd12196cdc",

opaque="c8202b69f571bdf3ece44c4ce6ee2466"
Figure 17.6: The server challenge for either Basic or Digest Authentication

Using multiple authentication schemes is not a good idea. The client is at


liberty to choose the strongest scheme it understands so there is a possibility
that it could be downgraded to Basic Authentication. This opens up a "man-in-
the-middle" attack where a malicious interceptor can pretend to be the client,
downgrade the authentication scheme and start acquiring passwords.
There are other techniques not explored here that can be practiced within
the scope of the Digest Authentication scheme by both client and server to
minimize the chance of standard "person-in-the-middle" attacks and raise the
quality of protection to ensure that both headers and data are safe from
tampering. But although Digest Authentication is somewhat more secure than
portrayed here, it is purely designed to be an improvement over the more
serious flaws of Basic Authentication and is not, nor was never intended to be,
a means for completely secure communication. Both Basic Authentication and
Digest Authentication schemes rely on a shared secret. Neither scheme a)
defines how the secret might be exchanged initially, b) allows client and server
to be cryptographically assured of each others identity, c) mandates the use of
the secret to guarantee that data exchanged between the two has not been
tampered with or d) mandates the use of the secret to encrypt the
conversation so that others may not see it. There are some attacks that can
only be prevented by sending HTTP requests and responses over a
cryptographically encrypted channel so that even if bad people can intercept
transactions then they are of no use. The Secure Sockets Layer (SSL) addresses
all of these concerns.
As an aside, the Apache SOAP project contains a really useful utility called
TcpTunnelGui that allows you to watch, amongst other things, HTTP traffic
between client and server. It can be found inside soap.jar within the
download at http://xml.apache.org/dist/soap/soap-bin-2.1.zip. The usage is as
follows.
java -cp <classpath>
org.apache.soap.util.net.TcpTunnelGui
<listenport> <host> <port>

602 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

The <classpath> parameter must point to soap.jar. It sits on port


<listenport> intercepting all traffic to and from the port <port> on server
<server>. So, if you were to type
java -cp c:\jars\soap.jar
org.apache.soap.util.net.TcpTunnelGui
9000 localhost 80
and then browse to http://localhost:9000 then you would
see the traffic between the browse client and the web server running on port
80 as it serves up the default page.

Copyright © 2001, DevelopMentor Inc. 603


Module 17: Java Distributed Security

Secure, encrypted communication


Cryptography allows data to be encrypted/decrypted with keys

• Symmetric keys good for bulk data


• Asymmetric keys good for signing or key exchange
• Certificates solve fragile public key problem
• SSL uses four-way handshake to set up secure encrypted channel
• Certs used to authenticate client/server to one another for secure session
key exchange
• HTTP over SSL (https) solves problems of Basic/Digest

604 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

Cryptography allows data to be encrypted with a key so that it can only be


decrypted with a "matching" key. There are two types of key encryption --
symmetric and asymmetric. A symmetric key represents a shared secret and
the same key is used to encrypt and decrypt. An asymmetric key is split into
two parts--the private key and the public key. Either can decrypt data
encrypted by the other. The private key is only known by a single entity and
the public key is known by everyone. If data is encrypted by the entity with its
private key, then everyone can decrypt the data and deduce it came from that
entity. If data is encrypted by anyone with the public key, it can only be
decrypted by the entity with the private key.
This highlights the two common uses of cryptography. One use is to encrypt
data so that nobody but the intended recipient can read it. This can be done
either by encrypting data with an entity's public key so that only the entity
with the corresponding private key can decrypt it or by using a symmetric key
shared by only two entities. The other use is to sign data so that the recipient
can tell which entity the data came from and that it has not been tampered
with since it was sent. This is achieved by the sender running a one-way
algorithm over the data to produce a fixed-length encoding termed a hash,
typically between 128 and 256 bits. The hash is then encrypted with the key
and sent along with the data--the data is still sent in the clear. The recipient
takes the encrypted hash and decrypts it. If the recipient can decrypt the hash,
then the recipient knows who the sender was. Then it runs the same one-way
algorithm over the data and compares hashes. If they are the same, then the
data has not changed since it was sent. Signing can be performed by an entity
encrypting the hash with its private key so that everyone can be sure the data
came from that entity. Alternatively, the hash could be signed by a symmetric
key so that it could only be verified by a recipient that has the symmetric key
(knows the shared secret).
So which do we use--symmetric or asymmetric keys? It turns out that
asymmetric encryption is fine for encrypting/decrypting a hash but is slow
when used for encrypting/decrypting bulk data. So the best bet is for two
parties to exchange a symmetric key for data encryption, valid for the lifetime
of the interaction between the two parties. But how best to exchange this
session key securely so that it cannot be seen and so that both parties really
know who they are sharing the key with? The answer is using asymmetric keys.
Not only do asymmetric keys lend themselves towards generating digital
signatures but also secure exchange of symmetric keys.
Alice and Bob want to exchange a session key. Alice generates a session key
and encrypts it with Bob's public key. She signs the encrypted session key with
her private key and sends the signed, encrypted session key to Bob. Bob can
use Alice's public key to verify the data came from Alice and only Bob can
decrypt the session key. Bob now has trust in Alice and the session key. Bob
now encrypts the session key with Alice's public key. He signs the encrypted
session key with his private key and sends the signed, encrypted session key

Copyright © 2001, DevelopMentor Inc. 605


Module 17: Java Distributed Security

back to Alice. Alice now has trust in Bob and the session key. This assumes, of
course, that Alice and Bob have already securely exchanged public keys. Even
though public keys can be read and used by anyone, what they cannot do is
send public keys to each other on the wire.
If Mallory were to intercept the key exchange he could just sit in the middle
and pretend to be Bob to Alice and Alice to Bob and read all traffic between
them. If Alice and Bob knew each other they could exchange public keys face
to face without Mallory being able to get in the middle. If not, they could use a
trusted intermediary, Trent (someone they had both securely exchanged keys
with in the past). Assume Alice and Bob both trust Trent and have already
obtained Trent's public key securely. Also suppose Trent trusts both of them
and has already obtained their public key's securely. Trent can put Bob's public
key and details in a package called a certificate, sign it and send it to Alice.
She knows it came from Trent and can trust the contents. Likewise, Trent can
place Alice's public key in a signed certificate and send it to Bob who knows it
came from Trent and has not been tampered with in transit. In fact, Trent
could issue Alice and Bob with their own certificates, signed by him. This way,
for example, Bob could authenticate himself to any other party that also
trusted Trent by just sending his certificate (signed by Trent) containing his
public key.
Of course, this authentication technique involving certificate exchange only
works amongst those parties who trust Trent. Those who have certificates
signed by Trudy cannot exchange certificates with those who have certificates
signed by Trent. Unless, that is, Trudy and Trent both have certificates
themselves that are issued and signed by someone they both trust, Todd. This
is termed a certificate chain. In this case, for Bob to authenticate to Carol
(who trusts Trudy) he must pass her both his certificate (signed by Trent) and
Trent's certificate (signed by Todd). In this way Carol can verify that Bob is
trusted by Trent who is trusted by Todd and that is OK because Trudy (who she
trusts) is also trusted by Todd. At the top of the tree there must be some single
certificate authority (CA) that everyone trusts and who is able to sign their own
certificates.
In the real world there is a standard for certificates called X.509 and there
are several CAs who are trusted by everyone and whose public keys are well
known, for example, Verisign. Certificates issued by Verisign are globally
recognized and Verisign's public key gets distributed with commercial client
and server software such as browsers and web servers. A company could act as
its own certificate authority to all of its departments but those certificates
would only be usable within the company, not globally.
So where are we? In order for two parties to authenticate each other they
exchange certificates and then they can use asymmetric encryption to
exchange a session key securely. From that point on, data can be encrypted or
signed using the shared session key. This is essentially what SSL does although
it's a little more complex than that. There are two modes that make sense in

606 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

SSL. First, mutual authentication where the caller and server exchange
certificates so they both know who each other are. Second, server
authentication where the server sends a certificate to the caller so the caller
knows who the server is. SSL uses a four-way handshake shown in 17.7 that
progressively builds up trust between the two parties. A vastly simplified
explanation follows, involving a client running on behalf of Alice and a server
running on behalf of Bob.

Client Hello
(random#
+ cipher-suite
list) Server Hello
(random# + cipher-suite
+ server cert
+ client cert request*)

Client Finish
(client cert*,
encrypted pre-master secret,
cert verification code*,
change cipher spec
Message Authentication Server Finish
Code) (change cipher spec,
MAC)

Figure 17.7: 4-way SSL handshake

Leg 1) Alice sends a random number and an ordered list of acceptable cipher
suites (each cipher suite indicates the algorithms to be used for data
encryption, signatures etc) to Bob.
Leg 2) Bob receives Alice's transmission and sends back a random number of
his own (independent of the client-generated random number), the chosen
cipher suite, his certificate and, optionally, a request for the client's (Alice's)
certificate.
Leg 3) Alice receives Bob's transmission and verifies Bob's certificate. If it is
valid she now has Bob's public key but cannot prove it's him on the other end. If
Bob asked her for her certificate then she sends it. Then she generates another
random number (called the pre-master secret) and encrypts it with Bob's public
key (so only he can read it) and sends that. Next she constructs a signature
(using her private key) of all the handshake data that has formed part of the
conversation up until this point and sends that. This is sometimes called the
certificate verification code. Following that she uses the pre-master secret to
generate all the keys required to perform data encryption and provide
signatures according to the cipher suite she negotiated with Bob. She then

Copyright © 2001, DevelopMentor Inc. 607


Module 17: Java Distributed Security

sends an instruction to say that she is going to start using the negotiated cipher
suite. Finally she sends a message authentication code (MAC). This is a
signature (using the signature generation key from the negotiated cipher suite)
of all the handshake data that has formed part of the conversation up until this
point.
Leg 4) Bob receives Alice's transmission. He verifies her certificate, if she
sent it, and if it is valid he now has Alice's public key but cannot prove it's her
on the other end yet. He then decrypts the pre-master secret and uses it to
generate all the keys required to perform data encryption and provide
signatures according to the cipher suite he negotiated with Alice. He now has
the same set of keys as Alice. This allows Bob to verify the MAC, and if it is ok
then he is sure it is Alice on the other end because the MAC protects the entire
conversation so far. Bob now sends an instruction to say that he is also going to
start using the negotiated cipher suite. Finally he sends a MAC, which is a
signature (using the signature generation key from the negotiated cipher suite )
of all the handshake data that has formed part of the conversation up until this
point.
Alice receives Bob's transmission and uses the negotiated cipher suite to
decrypt it and verify the MAC. If it is ok then she is sure it is Bob on the other
end because only he could have decrypted the pre-master secret used to
generate the key used to generate the MAC. They are done. Alice knows she is
talking to Bob and Bob may know he is talking to Alice (if he asked her for a
certificate). They have exchanged keys used for data encryption and to ensure
data integrity.
So much for the theory of SSL, let's look at the practice. Port 443 is reserved
for running HTTP over SSL and the associated URL scheme is https. To enable
server authentication the server must install a certificate. It could be a
certificate from Verisign (or some other third party CA) or from your own
internal CA for limited authentication. The details of enabling SSL for a web
server will be vendor specific. For instance, in tomcat 4 beta 1 server (the
Servlet 2.3 reference implementation) the process is described in the
$CATALINA_HOME/conf.server.xml configuration file:
a) Download and install JSSE 1.0.2 or later, and put the JAR files into
$JAVA_HOME/jre/lib/ext,
b) Edit $JAVA_HOME/jre/lib/security/java.security and add
security.provider.2=com.sun.net.ssl.internal.ssl.Provider,
c) Execute keytool -genkey -alias tomcat -keyalg RSA with a
password value of "changeit", and
d) Uncomment the SSL HTTP/1.1 Connector (to run on port 8443 by default)
in $CATALINA_HOME/conf.server.xml.
The client code needed to converse over SSL with a secure server turns out
to be relatively easy to write, as figure 17.8 shows. All that is required is to

608 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

load a security provider that does SSL (Sun-supplied in this case) and set a
system property.
import java.net.*; import java.io.*;

Security.addProvider(new
com.sun.net.ssl.internal.ssl.Provider());
System.setProperty("java.protocol.handler.pkgs",
"com.sun.net.ssl.internal.www.protocol");
URL url = new URL("https://www.secureplace.com");
HttpURLConnection con =
(HttpURLConnection)url.openConnection();
con.connect();
InputStreamReader ins = new
InputStreamReader(con.getInputStream());
BufferedReader bufReader = new BufferedReader(ins);
String strOutput = null;
do {
strOutput = bufReader.readLine();
if (strOutput != null)
System.out.println(strOutput);
} while (strOutput != null);
Figure 17.8: Programming SSL on the client

Copyright © 2001, DevelopMentor Inc. 609


Module 17: Java Distributed Security

Java distributed security


Servlets, JSPs and EJBs require secured access.
Security needs to be easy to setup and administer so
Servlets, JSPs and EJB have a declarative security
model

Copyright © 2001, DevelopMentor Inc. 611


Module 17: Java Distributed Security

Declarative security for Servlets


Container uses web application deployment descriptor to make security
decisions

• Does resource require client-server communication to be encryption or have


integrity?
• Does a resource have any authorization constraints?
• Does the application have particular authentication requirements?

612 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

It's time to explore the world of Servlet security configuration. The Servlet
container draws on information held in the web application deployment
descriptor file (web.xml) when making security-related decisions. The main
concerns of the container are a) whether the requested resource forces the
communication between the caller and the server to be encrypted or to have
integrity, b) whether a resource has any authorization constraints and c)
whether the application has particular authentication requirements. This is
illustrated in figure 17.9.

check if
secured resource
Web application

HTTP(S) request check


transport
requirements
web.xml Servlet
401 Unauthorized
check
403 Access Denied authentication
requirements
200 OK
check
authorization
requirements

Figure 17.9: Servlet container uses web application descriptor to make


security decisions

Copyright © 2001, DevelopMentor Inc. 613


Module 17: Java Distributed Security

Declarative authentication for Servlets


Container authenticates only if resources is secured

• Authentication technique specified in <login-config>


• BASIC, DIGEST, CLIENT-CERT or FORM
• FORM allows application to control login UI
• Specification is prescriptive about form field names
• Uses cookies to track caller
• BASIC and FORM not secure without SSL

614 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

A Servlet container will only authenticate a caller if they attempt to access a


secured resource within a given web application AND the container cannot
figure out who is making the call AND there is some application-wide
authentication required.
To secure a resource, an application-wide security constraint can be
associated with all resources within the web application that match (are
accessible via) a specified URL pattern. Figure 17.10 shows a minimal security
constraint for such a web collection, defined in the application deployment
descriptor. In fact, it specifies no constraints at all here but is sufficient to
prompt the container to think about authenticating in response to an HTTP GET
request targeted at the URL
http://someServer/secureApp/sales/salestargets.
<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>SalesStuff</web-resource-name>
<url-pattern>/sales/*</url-pattern>
<!-- Could be any HTTP verb or * for all -->
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
...
</web-app>
Figure 17.10: Configuring a minimal security constraint to trigger
authentication

If the container cannot figure out who the caller is it consults an application-
wide <login-config> setting defined in the same application deployment
descriptor. Figure 17.11 shows how to force the caller to authenticate via Basic
Authentication for any secured resource by setting the <auth-method>
setting to BASIC. HTTP Digest Authentication (DIGEST) and Client-side
Certificate Authentication (CLIENT-CERT), discussed earlier, are also
supported.

Copyright © 2001, DevelopMentor Inc. 615


Module 17: Java Distributed Security

<web-app>
...
<!-- auth-method could be FORM, BASIC, DIGEST,
CLIENT-CERT -->
<!-- realm-name only used for BASIC -->
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>homer</realm-name>
</login-config>
...
</web-app>
Figure 17.11: Configuring application-wide authentication for security-
constrained resources

With HTTP authentication the client is in control of the user interface to the
login process. Giving the <auth-method> setting a value of FORM allows the
web application to define its own login pages so it has control over the look
and feel of the login procedure. Figure 17.12 shows how to configure this in the
application deployment descriptor and figure 17.13 shows the possible format
of the corresponding pages. When FORM is specified as the <auth-method>
setting it is the container that performs the authentication check and not your
application. For this reason the Servlet specification defines that the name of
the "action" is "j_security_check" and the names of the "user name" and
"password" fields are "j_username" and "j_password". POST must be used as the
form method. When the container sees the "j_security_check" action it uses
some internal mechanism to authenticate the caller. If the logon succeeds and
the caller is authorized to access the secured resource then the container uses
a session-id to identify a logon session for the caller from that point on. The
container typically maintains the logon session with a cookie containing the
session-id. The server sends the cookie back to the client and as long as the
caller presents this cookie with subsequent requests then the container will
know who the caller is.
<web-app>
...
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
...
</web-app>
Figure 17.12: Form-based authentication configuration

616 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

<!-- login.jsp -->


<html><body>
<form method="POST" action="j_security_check" >
<input type="text" name="j_username">
<input type="password" name="j_password">
<input type="submit" value="Log on">
</form>
</body></html>

<!-- error.jsp -->


<html><body>
Logon failed or not authorized
</body></html>
Figure 17.13: Form-based authentication pages

If the login succeeds but the calling principal is not allowed access to the
requested resource then the server sends back a "403 Access Denied" response.
If the login fails then the server sends back the page identified by the <form-
error-page-setting>.
Form-based authentication suffers from the same problems as Basic
Authentication. It is obviously not secure by default as there is no strong
authentication of the server and the password is passed in the clear. It is
possible to force the form-based login interaction to take place over a secure
channel by specifying a transport guarantee for the secured resource, as shown
below.
Once the identity of the caller has been established it can be obtained by
the Servlet/JSP code calling HttpServletRequest.getUserPrincipal().
The identity will also, by default, be propagated whenever a downstream
Servlets or JSP is called.

Copyright © 2001, DevelopMentor Inc. 617


Module 17: Java Distributed Security

Declarative integrity/privacy for Servlets


For data passed between client and server

• Specified in <transport-guarantee> of secured resource


• NONE, INTEGRITY or CONFIDENTIAL
• Integrity, confidential normally imply SSL
• Must enable SSL on server to work
• Can make Basic or Form-based Authentication safe

618 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

It is possible to specify a security constraint that guarantees the level of


integrity/privacy for the data passed between caller and server. Figure 17.14
shows a <transport-guarantee> setting of CONFIDENTIAL that provides
data integrity (you can tell who it came from and that it has not been
tampered with since it was sent) and data privacy (nobody but the intended
recipient can see the data). Other possible settings are INTEGRITY (data
integrity but no data privacy) and NONE (no data integrity and no data privacy).
Commonly INTEGRITY and CONFIDENTIALity imply SSL and so the caller
accesses the resource using https (or something similar).
<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>SalesStuff</web-resource-name>
<url-pattern>/sales/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>
CONFIDENTIAL
</transport-guarantee>
</user-data-constraint>
</security-constraint>
...
</web-app>
Figure 17.14: Configuring data integrity/privacy level between caller and
server

If CLIENT-CERT was not specified in the <login-config> setting in the


application deployment descriptor then the SSL exchange involves the client
authenticating the server via its certificate.

Copyright © 2001, DevelopMentor Inc. 619


Module 17: Java Distributed Security

Declarative authorization for Servlets


Needn't write any security access check code

• Principals belong to roles


• Secured resources specify allowed roles
• Caller allowed/denied access based on role membership
• If access denied then Servlet/JSP code won't even run
• Early method-level access checks are good practice
• Server-managed resources may have additional sign-on/DACL

620 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

The Servlet container authenticates and does access checks as early as


possible. If any authentication scheme fails then the server sends back a "403
Access Denied" error. If authentication succeeds, or was not necessary because
the container already knew the caller's identity then the container checks that
the caller is authorized to access the requested resource.
The Servlet specification defines a mechanism by which web resources
(Servlets, JSPs and other static content) can be secured. Rather than perform
access checks based on the merits of an individual caller, the Servlet container
allows/disallows access based on the type of the caller, i.e. the role that a
user has within the system. A server administrator can define roles for a given
web application in its deployment descriptor, as Figure 17.15 illustrates. A role
is just a grouping of authenticated principals, normally defined by some
function such as Sales, Marketing etc. The means by which principals are
placed in roles is entirely vendor-specific and is not covered by the Servlet
specification. Once roles have been created and role membership defined, then
role-based security constraints can be applied to a web collection. Access to a
resource will be granted if either a) no authentication scheme is in place or b)
the web collection has no role-based security constraint or c) the caller is in at
least one role allowed access. Otherwise access is denied. Figure 17.16 shows
how to ensure that only members of the Sales role or the Managers role can
successfully request an HTTP GET to resources in the web collection matching
the URL pattern /sales/*.
<web-app>
...
<security-role>
<role-name>Sales</role-name>
</security-role>
<security-role>
<role-name>Managers</role-name>
</security-role>
<security-role>
<role-name>Developers</role-name>
</security-role>
...
</web-app>
Figure 17.15: Configuring roles

Copyright © 2001, DevelopMentor Inc. 621


Module 17: Java Distributed Security

<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>SalesStuff</web-resource-name>
<url-pattern>/sales/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Sales</role-name>
<role-name>Managers</role-name>
</auth-constraint>
</security-constraint>
...
</web-app>
Figure 17.16: Configuring role authorization

Carrying out role-based authorization as early as possible is a reasonable


solution. Remember that Java has no real notion of the identity of the
executing code and all security checks are based on where the code in the call-
stack came from. A Servlet container loads all Servlet/JSP-related code and
the origin of that code is quite tightly managed so its security policy will
generally be quite liberal. While it would be possible for the application server
to replace the Java Security Manager with one that performed access checks to
system and server resources based on who the code was executing on behalf of,
it is much easier to standardize on the role-based access technique. The caller
is either allowed access to the whole operation and all the resources implied by
that operation, or not. If access is denied the Servlet/JSP code never even gets
to run! If access checks are delayed until the code attempts to acquire
resources programmatically it is much harder to manage security
administration, it is harder to code and unnecessary code gets executed when
the operation is doomed to failure because of access denial.
Having said that, most application servers do offer some way of allowing
server-managed resources, such as JDBC connections, to be configured with
sign-on and access control information. This is mostly interesting as it allows us
to manage the sign-on to say, a database, in our code or let the container
manage it for us. Figure 17.17 shows how to specify in the application
deployment descriptor file that the container is required to manage sign-on to
the database referred to by this JNDI configured database connection. This
would allow the Servlet to call DataSource.getConnection() in its code
rather than the
DataSource.getConnection("fred","fredspassword") where
username and password must be explicitly specified.

622 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

<web-app>
...
<resource-ref>
<!-- Refers to some server resource pre-configured
with DACL and username/password -->
<res-ref-name>jdbc/MyDBPool</res-ref-name>
<res-ref-name>javax.sql.DataSource</res-ref-name>
<!-- Could be SERVLET -->
<res-auth>CONTAINER</res-auth>
<resource-ref>
...
</web-app>
Figure 17.17: Configuring resource authentication

Copyright © 2001, DevelopMentor Inc. 623


Module 17: Java Distributed Security

Programmatic security in a Servlet/JSP


May need to fine-tune security policy in code

• ServletRequest.getUserPrincipal()
• ServletRequest.isUserInRole()
• ServletRequest.isSecure()
• Server provides other details of secure channel as attributes
• Could use JSSE to roll your own security

624 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

Role-based security is good because we can keep the access control


configuration separate from the Servlet/JSP code. The programmer doesn't
need to write any security-related code at all if they don't want to. But how
realistic is that? Role-based security is a fairly static and inflexible approach--
either the caller passes the access check based on role-membership or not. If
they do then the resource is returned or the Servlet/JSP code starts executing.
If not a "403 Access Denied" response is sent back to the caller. However, it
may not be possible to work out whether access is allowed until run-time based
on questions such as "what is the callers credit limit?" In addition it may not be
possible to re-administer roles and role membership at run-time without closing
down the container. To deal with these kinds of scenario the programmer can
obtain information about the caller or the caller's role membership at run-time
and perform different logic on the basis of what is discovered. Figure 17.18
illustrates.
void doPost(HttpServletRequest req,
HttpServletResponse resp) {
Principal p = req.getUserPrincipal();
auditCall(p.getName());
if (req.isUserInRole("ManagersRole")) {
// Do some Manager stuff
} else if (ctx.isUserInRole("SalesRole")) {
// Do some Sales stuff
}
}
Figure 17.18: Programmatic security in a Servlet

Ordinarily, if role names were adjusted (as might be the case if the application
were being internationalized) then the Servlet/JSP code calling
isUserInRole() would need to change. To avoid this, a <security-role-ref>
element should be declared for each Servlet in the application that uses role-
based security and needs to call isUserInRole(). Figure 17.19 shows how.
The value of <role-name> is the (invariant) string used by the Servlet in the call
to isUserInRole() and the value of <role-link> is the (possibly variant) name
of the defined role. The container respects this mapping if present but if no
<security-role-ref> has been declared with a <role-name> that matches the
string passed to isUserInRole, the container defaults to checking against the
list of <security-role> elements defined for the application in its web.xml
deployment file.

Copyright © 2001, DevelopMentor Inc. 625


Module 17: Java Distributed Security

<web-app>
...
<servlet>
<servlet-name>salestargets</servlet-name>
<servlet-class>SalesTargets</servlet-class>
<security-role-ref>
<role-name>SalesRole</role-name>
<role-link>Sales</role-link>
</security-role-ref>
<security-role-ref>
<role-name>ManagersRole</role-name>
<role-link>Managers</role-link>
</security-role-ref>
</servlet>
...
</web-app>
Figure 17.19: Configuring role references

If a request was made over a secure channel then the servlet can find out via
ServletRequest.isSecure(). Additionally, the container associates some
of the characteristics of the secure channel with ServletRequest attributes
available to the Servlet if it calls ServletRequest.getAttribute(). The
cipher suite and the algorithm key-size are available as attributes named
"javax.servlet.request.cipher-suite" and "javax.servet.request.key-size" of type
String and Integer respectively. If there are SSL certificates associated
with the request then they appear as an attribute named
"javax.servlet.request.X509Certificate" of type array of
java.security.cert.X509Certificate. The Java 2 security APIs and
JSSE provides a bunch of APIs to cover all aspects of authentication, integrity
and privacy plus key and certificate management/manipulation. Due to lack of
space and time these are not covered here.
What if Basic Authentication is too insecure for your needs and SSL is too
heavyweight, and something in-between is required but Digest Authentication
is not be supported? Then you may have to be prepared to roll your own
security using the Java security APIs. The following snippets show how you
could code your own (extremely weak) alternative to Digest Authentication.
Figure 17.20 shows a skeleton class that represents a hash of a user name,
password and the time. The time is in there to give the hash an expiry and
provide limited defence against replay attack.

626 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

import java.security.*;

public class SecureHash {


...
public static String genHash(String user,
String pwd,
String time)
{
MessageDigest digest=MessageDigest.getInstance("SHA");
digest.update(user.getBytes());
digest.update(pwd.getBytes());
digest.update(time.getBytes());
byte hashBytes[]=digest.digest();
// Code to convert bytes to string omitted
return hashString;
}
public static boolean checkHash(String user,
String pwd,
String time,
String hash)
{
String tmphash = genHash(user, pwd, time);
boolean hashOK = tmphash.equals(hash);
if (!hashOK) return false;
// hash is ok, now check the timeout
return hashOK;
}
}
Figure 17.20: A simple hash class

The client would generate the hash and send it as part of the query string as in
figure 17.21.
import java.net.*;
import java.util.*;
...
String url="http://SomeServer/secureApp/sales/makeSale";
String date=(new Date()).toString();
String hash=SecureHash.genHash(name,password,date);
if (hash!=null)
url +=
"?"+"userID="+name+"&amp;gmt="+date+"&amp;hash="+hash;
URL url = new URL(urlString);
HttpURLConnection
con=(HttpURLConnection)url.openConnection();
con.connect();
Figure 17.21: Client use of the hash class

Copyright © 2001, DevelopMentor Inc. 627


Module 17: Java Distributed Security

Finally the Servlet would accept the request and authenticate the caller as
shown in figure 17.22.
protected void doPost(HttpServletRequest req,
HttpServletResponse res)
{
boolean logonOK=PullLogonFlagFromSession();
if (logonOK) //proceed
else {
String user=req.getParameter("userID");
String time=req.getParameter("gmt");
String hash=req.getParameter("hash");
String pwd=lookupUserPassword(userID);
logonOK=SecureHash.checkHash(user,pwd,time,hash);
if (logonOK) {
boolean PutLogonFlagInSession();
//proceed
}
else // return error
}
}
Figure 17.22: Servlet use of the hash class

628 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

EJB security
EJB has declarative role-based security too

• On a per-method basis
• No authentication technique specified
• No data integrity/privacy technique specified
• EJB server may have way of accepting credentials securely at JNDI lookup
time
• Authenticated caller propagates by default
• Programmatic security choices similar to Servlet

630 Copyright © 2001, DevelopMentor Inc.


Module 17: Java Distributed Security

EJB has role-based security that is almost exactly the same as for Servlets. You
can allow/deny access on a per-method basis. However, EJB says very little
about how authentication will take place--it is essentially server-specific.
There is a standard technique that allows authentication to take place when
the client performs a JNDI lookup on the EJB home. Figure 17.23 show how to
authenticate when talking to a Weblogic EJB server using its secure t3s (t3 over
SSL) proprietary protocol.
Properties p = new Properties();
p.put(Context.SECURITY_PRINCIPAL, "fred");
p.put(Context.SECURITY_CREDENTIALS, "fredspassword");
// Better pass them securely!
p.put(Context.PROVIDER_URL, "t3s://someServer:7002");
p.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
Context ctx = new InitialContext(p);
Object o = ctx.lookup("TellerSession");
TellerSessionHome th=

(TellerSessionHome)PortableRemoteObject.narrow(o,TellerSess
ionHome.class);
Figure 17.23: Authenticating to an EJB server

If authentication does take place and any role-based access checks allow the
method call to proceed then it is possible to programmatically obtain
information about the caller (EJBContext.getCallerPrincipal()) or the
caller's role membership (EJBContext.isCallerInRole()) and act
accordingly. If an EJB is called from a Servlet or another EJB then the default
behaviour is to propagate the authenticated principal with the call.

Copyright © 2001, DevelopMentor Inc. 631


Module 17: Java Distributed Security

Summary
• Servlet security mostly declarative
• Leverages HTTP authentication
• SSL for secure communication
• Authentication triggered by access to protected resource
• Can protect resources with transport guarantee
• Can protect resources with role-based authorization
• EJB has role-based security but not much else

632 Copyright © 2001, DevelopMentor Inc.


Module 18

Tag Libraries

Copyright © 2001, DevelopMentor Inc. 633


After completing this module, you should be able to:
 understand how tag libraries work
 understand how to write a simple tag
 understand how to write an iterator tag
 understand how to write a body tag
 understand how to define a scripting variable from a tag

634 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

JSP Tag Libraries


JavaServer Pages are designed to be authored not by
Java developers but by web developers who may
know no Java. Tag libraries give page authors a way
of extending the functionality of their web pages
without using Java explicitly on the page.

Copyright © 2001, DevelopMentor Inc. 635


Module 18: Tag Libraries

What is a tag library?


Functionality hidden behind XML like elements

• Can be used by page authors


• Java code is executed when tag is processed
• Give better separation of content and logic
• Extend standard actions defined by JSP specification

636 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

JSP authors are typically not going to be Java programmers, but JSP authors
will often want to include functionality on a page that cannot be represented
by standard HTML or standard actions. Rather than make JSP authors put Java
code on the page which breaks the separation of Model and View, and which is
difficult to maintain, JSP offers a mechanism that allows authors to use
extended behaviour without writing Java code. Developers are able to define
libraries that offer this extended behaviour, JSP authors use this code in the
form of custom actions, which are distributed as "Tag Libraries."
The way tags are used by a page author as is shown in figure 18.1. A tag
library is introduced with the <@taglib directive. This directive has various
forms, the simplest of which is shown here. The taglib directive is there to
allow the page compiler to locate the Java code that implements the tag. The
URI references one of three things, either a tld file--this is the "Tag Library
Descriptor", an XML file that describes the tag and its capabilities. The URI
could also reference a taglib map in the application's deployment descriptor--
the map then references the tag library. In these two cases, the classes that
make up the tag library must be available to the application, either in WEB-
INF/classes or as a JAR file in WEB-INF/lib. Finally the URI could reference the
.jar file that contains the tag library, the .jar file would itself contain the tld.

<%@ taglib uri="/tlds/dataaccess.tld" prefix="da" %>


<%@ taglib uri="/tlds/displaytable.tld" prefix="display" %>

<HTML>
<BODY>
<HR>
<da:connection driverName="sun.jdbc.odbc.JdbcOdbcDriver"
sourceName="jdbc:odbc:pubs" >
<da:query id="rs" queryString="SELECT * FROM authors" >
<display:initialiseTable resultsetName="rs">
<display:tableBody />
</display:initialiseTable>
</da:query>
</da:connection>

Figure 18.1: A JSP containing tags

Notice that the <@taglib directive also contains a "prefix". This is essentially
the "namespace" for the tags defined within this tag library. This means that
any element defined on the page using this prefix identifies a tag specified
within the tag library identified by the tag library descriptor that defines that
prefix. So for example the <display:tableBody /> element uses the "display"
prefix which references the "displaytable.tld" tag library descriptor, so
information about the "tableBody" tag will be found in that .tld file.

Copyright © 2001, DevelopMentor Inc. 637


Module 18: Tag Libraries

The diagram tries to show some of the key features of tags. Tags can have
attributes that are used to pass data to the tag, which the tag can then act
upon. Tags may be nested; there is a parent-child relationship between tags,
and nested tags can get a reference to the Java object that represents their
parent. In fact a nested tag can get a reference to any of its ancestor tags.
Tags can have "bodies" and may process those bodies if they need to, i.e. the
"data" that is the body of the tag is passed into the tag and the tag is able to
use that data.

638 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

Tag handlers
Handle different types of events

• May only handle start and end events


• May also process tag body
• Tag handler is executed for each action on the page

640 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

There are three distinct kinds of tags, "simple" tags, "iteration" tags and "body"
tags. Each of these tags has a well-defined life-cycle. We will cover each in
more detail as we go through the chapter. Basically, Simple tags are tags that
do not want to process their "body", i.e. any data between the start element
and the end element of the tag is totally transparent to the code "behind" the
tag, and in fact this code never sees the data. Simple tags have a doStartTag
method that is called when the starting element of the tag is encountered, and
a doEndTag method that is called when the tag's end element is encountered.
If the tag is simply an empty element then doStartTag and doEndTag are
still called. Iteration tags extend simple tags and have the ability to iterate
over a body multiple times. Iterator tags don't get to process their bodies, but
the body could be another tag, this nested tag may then be processed multiple
times. Finally, body tags are tags that want to process whatever data lies
between the start and end elements of the tag. This body is input "data" to the
tag; figure 18.2 shows an example of a tag with a body.

<a:someTag> Start of Tag

This tags's body Tag's 'body'

</a:someTag > End of Tag

Figure 18.2: A JSP containing tags

Copyright © 2001, DevelopMentor Inc. 641


Module 18: Tag Libraries

Simple Tag
Tag is used if the tag never needs to process its body

• Tag may have a body (specified in the library descriptor)


• doStartTag may return SKIP_BODY
• doStartTag may return EVAL_BODY_INCLUDE

642 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

Simple tags are used when the tag can get all of its data from the tag
parameters, the tag may still have a body, i.e. it may consist of "startelement-
body-endelement" but the tag never gets to see its body, and so can never
process that data. For all tags when the tag is processed doStartTag is
called, for a simple tag this method returns either SKIP_BODY, meaning the
body of the tag should not be included in the output produced by this page, or
EVAL_BODY_INCLUDE, which means the body of the tag is to be output
unchanged, normally the tag will return EVAL_BODY_INCLUDE.
To write a simple tag the tag interface has to be implemented. This
interface contains six methods, as shown in figure 18.3. Four of these methods
can be implemented in a standard way, leaving only two up to the tag author.
The two non-standard methods are doStartTag and doEndTag, because of
this the servlet API contains an adaptor class called TagSupport that provides
implementations of the standard methods. This class is also shown in figure
18.3. Most authors of a simple tag will extend the TagSupport class rather
than implement tag. doStartTag and doEndTag define the tag's lifecycle;
these are called when the start and end elements respectively are encountered
on the page. setParent, setPageContext and release are called by the
page to initialise and de-initialise the tag. We will talk more about these later.
getParent is used by the tag author to retrieve a reference to the tag's
parent, if the tag is nested.
// tag interface
int doStartTag ()
int doEndTag ()

Tag getParent()
void setParent(Tag t)

void release()
// TagSupport void setPageContext (PageContext pc)
// methods from Tag
static Tag findAncestorWithClass (Tag from, java.lang.Class klass){}

java.lang.String getId() {}
void setId(java.lang.String id) {}

java.lang.Object getValue(java.lang.String k) {}
java.util.Enumeration getValues () {}
void removeValue (java.lang.String k) {}
void setValue (java.lang.String k, java.lang.Object o ){}
public int doAfterBody()

Figure 18.3: Tag interface and TagSupport class

The TagSupport class implements the methods of the tag interface plus
some other helpers. The three methods we care about are

Copyright © 2001, DevelopMentor Inc. 643


Module 18: Tag Libraries

findAncestorWithClass, getId and setId. findAncestorWithClass


simply walks up the "ancestor" hierarchy looking for a reference to a Java
object of a particular type. This helps if the child is nested and wants to get a
reference to a particular Java class that it knows is somewhere in the hierarchy
but is not necessarily the tags parent.
If a tag is defined as having attributes (and we will see how this is done in a
moment) the value of those attributes have to be passed to the tag. The
mechanism used to set the attribute values follows that used by Java Beans,
i.e. the tag has a setXXX method, where "XXX" matched the name of the
attribute. Because it was thought that many tags would have an "id" attribute
TagSupport contains a setId helper method, it also contains the
corresponding getId method. The "value" methods are spurious and should be
deprecated in future versions of the specification.
Figure 18.4 shows the code for a basic "simple" tag and how that tag may be
referenced on the page. The code, first of all. The Java class that implements
the tag is called Simple and it extends TagSupport. The class has a data
member m_secondName, which will hold the value of a "secondName"
attribute. The class has a corresponding setSecondName method that will be
used by the container to set the value of the attribute. The most interesting
part of the "Simple" tag is the doStartTag method. For simple tags, either
this method or doEndTag is where most of the work will take place.
doStartTag will run any business logic and produce any output it needs to.

644 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

<%@ taglib uri="/simpletags.tld" prefix="simple" %>


Some HTML
<simple:tagId id="fred" secondName="bert"/>
Some more HTML

public class Simple extends TagSupport


{
String m_secondName
// id is member of TagSupport

public int doStartTag() throws JspException


{
// do business logic
// retrieve out from pageContext
JspWriter out = pageContext.getOut();
// output any HTML
return EVAL_BODY_INCLUDE;
}

public void setSecondName(String str)


{
m_secondName = str;
}
}

Figure 18.4: Example of Coding and using a Simple

The page containing the tag is also shown in figure 18.4, and has a taglib
directive that introduces the tag to the page. This directive specifies the tag
prefix as "simple". The tag itself is used in the <simple:tagId element.
Notice that the prefix is "simple" and the name of the tag is "tagId". This is not
the same as the name of the class that implements the tag, which means that
somewhere there has to be a tie up between the tag name, and the Java class
that implements the tag, that tie up is in the deployment descriptor.
Figure 18.5 shows the deployment descriptor for this tag library. Here we
define the "name" of the tag (tagId in this case) and the name of the Java class
that provides the implementation (com.develop.taglib.Simple). The
descriptor also defines (amongst other things) the attributes that the tag
expects. In this case there are two attributes, "id" and "secondName", id is
required, secondName is not. Notice that our tag code has a setSecondName
method but not a setId method, because the setId method is supplied by
TagSupport.

Copyright © 2001, DevelopMentor Inc. 645


Module 18: Tag Libraries

<tag>
<name>tagId</name>
<tag-class>com.develop.taglib.Simple</tag-class>
<body-content>empty</body-content>

<attribute>
<name>id</name>
<required>true</required>
</attribute>

<attribute>
<name>secondName</name>
<required>false</required>
</attribute>
</tag>

Figure 18.5: Example of a Deployment Descriptor

So, what is the flow of control when the page executes the tag? The tag first
has to be created, so when the JSP "engine" sees a start element, it looks in the
tag library descriptor for the matching Java class and creates an instance of
that class. Once the object has been created it needs to be initialised. There
are several methods that need to be called as part of the initialisation. The
engine calls setPageContext passing the tag the JSP pageContext. From
this the tag can get a reference to the objects used by the generated servlet,
such as the HttpServletResponse, HttpServletRequest and the
JSPWriter. Once that has been passed in the container then sets the tag's
parent, and each of the tag's attributes (id and secondName in this case). Once
the tag has been fully initialised the container calls doStartTag. This is
where the tag will do its work. Once doStartTag has ended the container
calls doEndTag. This particular use of the tag has now finished, but the
container is free to re-use this instance for another instance of the tag on the
page. Once the container has finished with the tag entirely, it calls release.
Figure 18.6 shows this.

646 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

JSP engine sees tag (<simple: tagId…>)

Instantiates a variable of correct type


from tld file
(com.develop.taglib.Simple)

Initialises tag instance with


pageContext

Sets the instance's parent, id and any


other attributes (eg 'secondname’ )

Calls instance's doStartTag method

Tag instance does its work

Calls instance's doEndTag method

Calls instance's release method (I'm


finished with this instance)
Figure 18.6: Flow of Control for a Simple Tag

Copyright © 2001, DevelopMentor Inc. 647


Module 18: Tag Libraries

Iteration Tags
Tag is used if looping is required

• Tag may have a body (specified in the library descriptor)


• doAfterBody may return SKIP_BODY
• doAfterBody may return EVAL_BODY_AGAIN

648 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

Sometimes a tag needs to output its body multiple times. This typically
happens when the body of the tag is another tag. For example, imagine the
parent tag outputs a table "header" and the child tag outputs a table "row". The
parent may have a list of data (a JDBC ResultSet for example), and it may want
the child to output a single row for each entry in the table. In that case, the
parent wants to control how often the child is executed. To do this the parent
has to be an "iteration" tag. As figure 18.7 shows the iteration tag is a simple
tag with an extra method doAfterBody. This method is called after
doStartTag and determines whether the tag "loops" or not. If doAfterTag
returns SKIP_BODY that signifies the end of the iteration, returning
EVAL_BODY_AGAIN causes the iteration to continue. Figure 18.8 shows a very
simple example of this and figure 18.9 shows the flow of control for an
iteration tag.

// IterationTag interface
int doAfterBody()
Figure 18.7: Iteration Tag Interface

public class SimpleIterator extends TagSupport


{
int loopCount ;
public void setLoopCount (int loopCount ){
this.loopCount = loopCount ;
}
public int doStartTag (){
return EVAL_BODY_INCLUDE;
}
public int doAfterBody (){
while(--loopCount > 0)
return EVAL_BODY_AGAIN;
return SKIP_BODY;
}
}

Figure 18.8: Example of Iteration Tag Code.

Copyright © 2001, DevelopMentor Inc. 649


Module 18: Tag Libraries

Engine sees (<simple:withbody>)


… As before…
Calls instance's doStartTag method
which returns EVAL_BODY_INCLUDE
doAfterBody called

doAfterBody returns EVAL_BODY_AGAIN


body is re-evaluated

doAfterBody returns SKIP_BODY


processing continues at next line
Figure 18.9: Iteration Tag Flow

650 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

Body Tags
BodyTag is used if the tag needs to process its body

• Tag may never have a body (specified in the library descriptor)


• doStartTag may return SKIP_BODY
• doStartTag may return EVAL_BODY_BUFFERED
• doInitBody and doAfterBody called
• Passed a BodyContent object that "contains" the body

652 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

BodyTags are used if the tag handler wants to process the data that makes up
the body of the tag. The lifecycle of BodyTags is slightly more involved than
simple and iteration tags, and the output model is a lot more complicated.
BodyTags process the body of the tag, and part of the lifecycle is taken up with
the tag initialising the body before use, and being passed the body to process.
A tag may not want to process its body; in this case it doStartTag returns
SKIP_BODY. If the tag does want to process its body then doStartTag returns
EVAL_BODY_BUFFERED and doInitBody and doAfterBody are called. Both
of these methods work on a BodyContent object that is passed to the tag as
part of its initialisation.
Figure 18.10 shows the classes and interfaces used to write body tags. The
BodyTag interface extends IterationTag and provides two extra methods
setBodyContent and doInitBody, while BodyTagSupport extends
TagSupport and provides two extra helpers, getBodyContent and
getPreviousOut. The setBodyContent method is called by the servlet
container to and passes the tag a BodyContent object, this object will
contain the data that makes up the body of the tag. The BodyTagSupport class
will simply store the BodyContent away and provides the helper
getBodyContent to retrieve it again. getPreviousOut will be discussed
later.

// bodytag interface
void setBodyContent(BodyContent b)
void doInitBody()

// BodyTagSupport
// methods from BodyTag
BodyContent getBodyContent () {}
JspWriter getPreviousOut () {}
Figure 18.10: Body interface and BodyTagSupport class

Figure 18.11 shows the BodyContent object. This object is schizophrenic, it


extends JspWriter, but you can also read from it. For now the important
methods are getString, which returns the data as a java.lang.String
and getReader, which returns a java.io.Reader that can be used to read
the body data. As for the other methods: flush does nothing, there is
nowhere to flush the body to; clearBody clears the data in the bodyContent
object; writeOut writes the data in the bodyContent to the specified
Writer and getEnclosingWriter will be examined later.

Copyright © 2001, DevelopMentor Inc. 653


Module 18: Tag Libraries

// derives from JSPWriter


void clearBody(){}
void flush(){}
JspWriter getEnclosingWriter() {}
java.io.Reader getReader() {}
String getString() {}
void writeOut(java.io.Writer out) {}
Figure 18.11: The BodyContent class

Body tags can have two types of "body data" These data types are specified in
the .tld file (in the <bodycontent> section) and may be "tagdependent" or "jsp".
If the body is marked as "tagdependent", then the data is passed to the tag
unchanged. If the body is marked as "jsp" then the container first "evaluates"
the body of the tag, executing any JSP "code" it finds there, and passes the
result of this evaluation to the tag. Figure 18.12 shows two examples of using a
body tag on a page, one with the bodycontent set to "tagdependent" and the
other with the bodycontent set to "jsp". In the first case, the tag's
BodyContent object will contain the text "The body of the tag", while in the
second case the BodyContent object will contain the result of the evaluation
of <%=bean.getName() %>.

<tag>
<name>withBody</name>
<tagclass>com.develop. taglib.SimpleWithBody</tagclass>
<bodycontent>tagdependent | jsp</bodycontent>

</tag>

<simple:tagWithBody> <simple:tagWithBody>
The body of the tag <%= bean.getName() %>
</simple:tagWithBody> </simple:tagWithBody>

Figure 18.12: Example of "tagdependant" and "JSP" Body Tags

Figure 18.13 brings together the three parts of the tag, the .tld file, the JSP
page and the tag code itself. Notice that the tag's doStartTag method returns
EVAL_BODY_BUFFERED and that doAfterBody will then be called.

654 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

<%@ taglib uri="/simpletags.tld" prefix="simple" %>


Some HTML
<simple:withBody id="fred" secondname="bert">
<%= logonBean.getName() %>
</simple:first>
Some more HTML

<tag>
<name>withBody</name>
<tagclass>com.develop.taglib.WithBody</tagclass>
<bodycontent>jsp</bodycontent>
public class WithBody extends BodyTagSupport
<attribute> {
<name>id</name>
<required>true</required> public int doStartTag() throws JspException
</attribute> {
return EVAL_BODY_BUFFERED;
<attribute> }
<name>secondname</name>
<required>false</required> public int doAfterBody() throws JspException
</attribute> {
</tag> // access BodyContent
// and process it
return SKIP_BODY;
}
}

Figure 18.13: Example of a Body tag

The lifecycle of a body tag starts the same as a simple tag, i.e. the tag is
initialised and doStartTag is called. After the tag has been initialized the
container will create an empty bodyContent object and call
setBodyContent giving the tag a reference to the empty bodyContent
object. The container then calls doInitBody. This gives the tag the option of
initialising the body content before the actual data is written to the
bodyContent by the container. The container now evaluates the
bodyContent and writes the results of this evaluation to the bodyContent.
Finally, the container calls doAfterBody allowing the tag to process the body.
Like an iteration tag a body tag can iterate by having doAfterBody return
either EVAL_BODY_AGAIN. Figure 18.14 shows this diagrammatically, and
18.15 shows the code generated by a body tag.

Copyright © 2001, DevelopMentor Inc. 655


Module 18: Tag Libraries

Engine sees (<simple:withbody>)


… As before…
Calls instance's doStartTag method which
returns EVAL_BODY_BUFFERED
Empty BodyContent object created
doInitBody called
Body evaluated and BodyContent
initialized
doAfterBody called
doAfterBody returns
EVAL_BODY_BUFFERED
body is re-evaluated

doAfterBody returns SKIP_BODY


processing continues at next line
Figure 18.14: Flow of Control for a Body Tag

<tag:parentTag>
Hello World
</tag:parentTag

parentTag = new ParentTag();


if(parentTag.doStartTag() != Tag.SKIP_BODY){
out = pageContext.pushBody();
parentTag.setBodyContent((BodyContent) out);
parentTag.doInitBody();
do {
out.write("Hello World");
} while (parentTag.doAfterBody() == BodyTag.EVAL_BODY_TAG);
out = pageContext.popBody();
}
parentTag.release();

Figure 18.15: Example of Body Tag showing the usage and the generated
code.

Notice that to create a new, empty bodyContent object,


pageContext.pushbody is called. This puts the "current" JSPWriter onto the
stack and assigns the "out" intrinsic to the bodyContent created by the call to
pushBody. Remember the "out" intrinsic is available through a call to
pageContext.getOut, which means that when a body tag calls

656 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

pageContext.getOut, the JSPWriter returned is not the JSPWriter that


allows the JSP page to write back to the client. The JSPWriter returned is the
"out" created by the call to pushBody, and this is just the tag's bodyContent
object, i.e. the tag's own body. To send output back to the caller, a body tag
has to get access to the "top-level" out. It does this by calling
getPreviousOut, a helper method of TagSupport. Calling
getPreviousOut gives the tag access to the next "out" up the stack, which
for a top level tag (i.e. a tag that isn't nested) is the "out" intrinsic. A body tag
has two mechanisms to allow it to write back to its caller--either call
getPreviousOut().write(), or call
bodyContent.writeOut(getPreviousOut()), these will be discussed
later.

Copyright © 2001, DevelopMentor Inc. 657


Module 18: Tag Libraries

Nested Tags
One tag can nest within another

• Useful if child wants to use output of a parent tag


• Maybe update properties or supply parameters
• <simple:parent ... >
• <simple:child ... />
• </simple:parent>
• Child can access parent (getParent or findAncestorWithClass)
• Child can have a body or other child tags
• Child writes to parent's body (getPreviousOut().write())

658 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

One tag can be "nested" within another tag, i.e. tags can have a parent-child
relationship. This nesting can go arbitrarily deep. This is similar to how XML
and HTML works, for example <table>s have <tr> elements, which have <td>
elements. Nested tags typically co-operate, which means that the child tag
often needs to get a reference to its parent; TagSupport has a helper
function getParent that retrieves a reference to the parent tag. Of course
the child may be nested arbitrarily deeply, in which case getParent won't
retrieve the correct reference. There is another helper function,
findAncestorWithClass that walks the ancestor hierarchy looking for a
reference to the specified class. If a "parent" tag is an iteration tag it can
"execute" the nested tag multiple times by returning EVAL_BODY_AGAIN from
doAfterBody
Figure 18.16 shows the code generated for a nested tag. Notice that the
nested tag is called inside a do...while. At the top of this loop the code calls
doStartTag followed by pushBody and then setBodyContent. As discussed
above, a body tag calls getPreviousOut to write its output, but what
happens when a nested tag calls getPreviousOut? Remember that
getPreviousOut returns the "previous" out on the stack, which is the out
pushed onto the stack by the previous call to pushBody, looking at the code
you will see that the previous out pushed onto the stack is the parent tag's
bodyContent. This means that when a nested tag calls
getPreviousOut().write(), or
bodyContent.writeOut(getPreviousOut()), it's writing to it's parent's
body--which is exactly what you want to happen.

Copyright © 2001, DevelopMentor Inc. 659


Module 18: Tag Libraries

<tag:parentTag>
<tag:childTag/>
</tag:parentTag>
parentTag = new ParentTag();
if(parentTag.doStartTag() != Tag.SKIP_BODY){
out = pageContext.pushBody();
parentTag.setBodyContent((BodyContent) out);
parentTag.doInitBody();
do {
childTag childTag = new childTag();
if(childTag.doStartTag() != Tag.SKIP_BODY) {
out = pageContext.pushBody();
childTag.setBodyContent((BodyContent) out);
childTag.doInitBody();
do {
} while (childTag.doAfterBody() == BodyTag.EVAL_BODY_AGAIN);
out = pageContext.popBody();
}
} while (parentTag.doAfterBody() == BodyTag.EVAL_BODY_AGAIN);
out = pageContext.popBody();
}

Figure 18.16: Example of Nested Tag showing the usage and the generated
code.

660 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

Outputting Data
Top level and nested tags behave differently

• Top level tag always writes to the intrinsic out


• Nested tag always writes to parent's body
• Simple tags always write to "out"
• JspWriter out = pageContext.getOut();
• Body tags always write to "previous" out
• JspWriter out = getPreviousOut()
• bodyContent.writeOut(getPreviousOut());

662 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

This slide summarises the previous discussion on producing output from tags.
When a top-level (non-nested) tag calls pageContext.getOut it always gets
the "out" intrinsic. Simple tags always call pageContext.getOut. If the tag is
a top level tag, then this returns the "out" intrinsic. If the tag is nested this call
returns the parent's bodyContent. Body tags always call
getPreviousOut().write(), or
bodyContent.writeOut(getPreviousOut()), which for a top-level tag
returns the "out" intrinsic and for a nested tag returns the parent's body. So the
rules are simple: simple tags always call pageContext.getOut and body tags
always call getPreviousOut().write(), or
bodyContent.writeOut(getPreviousOut()).

Copyright © 2001, DevelopMentor Inc. 663


Module 18: Tag Libraries

Creating Script Objects With Tags


Tags can be used to create Java objects. These
objects can be used after the tag has finished
processing

Copyright © 2001, DevelopMentor Inc. 665


Module 18: Tag Libraries

Defining Scripting Variables


May want an object created in tag handler to be available elsewhere

• Have to let JSP engine know we want to do this


• Has to know "type" of variable
• Declare a TagExtraInfo for this tag
• Specify this in TLD

666 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

The largest use of custom actions is to create Java beans through the
jsp:useBean tag. This tag defines a bean variable and either creates the
bean or locates the bean in the specified "scope" and assigns that reference to
the variable. Custom actions (tag libraries) can also define beans (or scripting
variables as they are called in the specification). Figure 18.17 shows an
example of a tag that has defined a script variable (called "result"). A scripting
variable has a variable "name", a Java type, a "scope" and a "lifetime." The
scope is the same as that for the jsp:useBean action, i.e. one of 'page',
'request', 'session' and 'application' the lifetime defines when the scripting
variable is made available to the rest of the page, either from the starting tag
element onwards, from the ending tag element onwards, or only within the
body of the tag.

<tag:sometag id="result" >


<% result.someMethod(); %>
</tag:sometag >

<%= result.
toString() %>
Figure 18.17: Example of a Tag Creating an Object to Script

As shown in figure 18.18, this information is defined in a class that extends


TagExtraInfo, and that is referenced in the .tld file. The TagExtraInfo
class has a method called getVariableInfo that returns a VariableInfo
array that describes the script variables this tag will create. It's here that the
id, type and lifetime are defined. Figure 18.19 shows the tag creating the
variable. The variable is made available to the page by calling
pageContext.setAttribute, in this example the two variable version is
used, this puts the variable into 'page' scope. There is also a three parameter
version that allows the code author to specify the scope.

Copyright © 2001, DevelopMentor Inc. 667


Module 18: Tag Libraries

<%@ taglib uri="/simpletags.tld" prefix="simple" %>


Some HTML
<simple:rsScriptVar id="rs" >
<%= rs.getString(1) %>
</simple: rsScriptVar >
<tag> Some more HTML
<name> rsScriptVar </name>
<tagclass>com.develop.taglib. RsScriptVar </tagclass>
<teiclass>com.develop.taglib.ScriptVarTEI</teiclass>


public class ScriptVarTEI extends TagExtraInfo
</tag>
{
public VariableInfo[] getVariableInfo(TagData data)
{
// create a VariableInfo
VariableInfo info = new VariableInfo( data.getId(),
"java.sql.ResultSet",
true,
VariableInfo.NESTED );
VariableInfo[] back = { info };

return back;
}
}

Figure 18.18: Example of Defining a Script Variable Created by a Tag

ResultSet rs = null;
try
{
Connection conn = tag.getConnection();
m_stmt = conn.createStatement();
rs = m_stmt.executeQuery(m_QueryString);
}catch(Exception e)
{
throw new JspException(e.getMessage());
}
pageContext.setAttribute(getId(), rs);

Figure 18.19: Example of Defining the scope of a Script Variable Created by


a Tag

Finally, the lifetime of the bean is specified in the VariableInfo, it has one
of three values AT_BEGIN, AT_END and NESTED. As shown in figure 18.20,
AT_BEGIN means the variable will be available after the start tag, AT_END
means the variable is available after the end of the tag and NESTED means the
variable is only available within the body of the tag.

668 Copyright © 2001, DevelopMentor Inc.


Module 18: Tag Libraries

VariableInfo info = new VariableInfo( data.getId(),


"java.sql.ResultSet",
true,
true,
VariableInfo.NESTED );

[] back = { info };

// ----------------------------------------

<quux:foo … > AT_BEGIN and NESTED

</quux:foo> AT_END

Figure 18.20: Specifying when a script variable is available

Copyright © 2001, DevelopMentor Inc. 669


Module 18: Tag Libraries

Summary
• JSP authors are not necessarily Java developers
• Want to keep Java code off a JavaServer Page
• Custom actions (tag libraries) allow the use of elements as a replacement
for Java code
• Three types of tags, simple, iterator and body
• Tags can also create scripting variables

670 Copyright © 2001, DevelopMentor Inc.


Module 19

Java Messaging

Copyright © 2001, DevelopMentor Inc. 671


Asynchronous, disconnected and reliable communication

After completing this module, you should be able to:


 Appreciate how the flexibility of messaging solves issues with RPC
 Understand the JMS object model
 Use JMS to asynchronously send and receive messages
 See how JMS is integrated with EJB 2.0
 Learn about EJB's message-driven bean

672 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

Messaging
Standard RPC mechanisms have issues. Messaging
offers a much more flexible communication
alternative.

Copyright © 2001, DevelopMentor Inc. 673


Module 19: Java Messaging

Problems with RPC


RPC is good for synchronous, blocking requests

• Not all parts of system are synchronous


• Not all parts of system tied to single request/response model
• Not all parts of system are tightly coupled
• Some parts of system require reliable communication

674 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

RPC is a function call paradigm layered on top of messaging, as figure 19.1


shows. Most RPC systems define an interface that contains a bunch of related
methods that need to be implemented in one place and called from another. A
tool then parses the interface definition and spits out a "stub" and a "skeleton"
for each method. In Java RMI the tool is rmic. The stub is an implementation
of the method that is executed locally by the caller. Its implementation takes
the call, marshals it into a request message and forwards it to wherever the
actual method implementation lives. The local stub method now blocks
awaiting the response message. The skeleton sits close to the real method
implementation listening for incoming request messages. It unmarshals the call
from the request message and replays it against the real method
implementation. The skeleton then takes the output parameters and the result
from executing the real method and marshals them into a response message. It
sends the response message back to the waiting local stub method. It receives
the response message, unmarshals it and gives the results back to the caller. So
the caller feels like it is calling a local method and the real method feels like it
is being called by a local caller. A synchronous, blocking method call
mechanism has been layered on top of messaging in order to allow developers
to work with a familiar paradigm. However, this model proves to be inflexible
and restrictive in some cases.

public long add(long l1,long l2);

compiler
public long add(long l1,
long l2) {
long I = add(5,10); return l1+l2;
}

Request message
Method: add
add Params: 5(long),10(long) add
method method
stub Return: 15(long) skeleton

Response message

Figure 19.1: Remote Procedure Call model

Standard RPC mechanisms are a good way to deliver synchronous, blocking


requests but there are many other data flow options that it doesn't lend itself
to. Not all parts of the system are synchronous and blocking. Work may need to
be performed asynchronously without blocking the current thread. We may
think of spinning up another thread to perform such work but this assumes that

Copyright © 2001, DevelopMentor Inc. 675


Module 19: Java Messaging

we are allowed to (think EJB) and also that the work can be done in the same
process. Not all requests require a response and the caller doesn't want to have
to wait for the callee to process the request just to get a response that wasn't
needed. Not all parts of the system have overlapping lifetimes. It may be
necessary to dispatch a request to an intended recipient that isn't even running
yet. It would be nice if the request could be processed the next time the
intended recipient connects to the system. If an RPC call fails then the caller
will get a communications error but it is up to the caller to figure out what to
do next. Did the request get there? If it did, was it processed? If it was, what
was the outcome? For non-idempotent operations that have side-effects (such
as "withdraw $100 from my account") the caller has to be careful about re-
executing the call. RPC is no help here as it has no notion of making a
"guaranteed delivery" request/response without the programmer providing
extra application-level semantics to achieve reliable, transacted
communication.
So RPC has issues - many more than mentioned here - and it seems that the
problems all stem from the tightly-coupled nature of the caller and callee and
the restrictive flow of messages tied to a standard request/response model.
For example, caller and callee must be executing at the same time, the call
must be synchronous and blocking and the call must return a result. If this RPC
veneer is stripped away then we are left with messaging.

676 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

Messaging is an alternative
Strip the veneer off RPC

• Message = headers(routing info) + payload


• Delivery is asynchronous
• Destination = named message repository on n/w
• Decouples message producer/consumer
• Runtime = variety of delivery semantics
• Reliable, transacted, prioritized, deadline-based, publish-and-subscribe etc
• Application now has many more data flow options
• Fire-and-forget, multicast, disconnected, load-balancing, flow control etc
• RPC model is simpler in most cases

678 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

A messaging system is the part of the runtime that delivers messages


asynchronously to some destination with a specified quality of service. Whilst a
messaging system may provide several delivery models, it defines no
application-level semantics and is purely concerned with getting a message
from one place to another as quickly and safely as possible.
A message is a communication between a single producer application and
one or more consumer applications. It is made up of a header, additional
properties and the body as shown in figure 19.2. The header comprises
information understood by the messaging system, which it uses to control the
routing, and delivery of the message. Examples of header fields might be
message priority, which affects how quickly the message gets delivered relative
to other messages, or message deliver guarantee, which affects the robustness
of the message in the face of system failure. Additional properties normally
identify application specific information, which is only understood by producer
and consumer as part of their application-level protocol. The message body is a
structured or unstructured stream of bytes identifying the data of the message
- the payload. It identifies the details of the request, response or event that
the message represents. Obviously the format and content of the message body
must be understood by both producer and consumer.

Header Properties Body

Routing and delivery Payload - the request,


info used by system Response or event
Application-level
properties
Figure 19.2: Anatomy of a message

A destination is a named message repository on the network that provides a


level of indirection between a producer and consumer. A message producer
locates a destination, generates a message addressed to that destination and
then instructs the messaging system to send it. The sender returns immediately
without blocking. The messaging system then attempts to deliver the message
to the chosen destination. Messages may fail to get to their destination for all
kinds of reasons, for instance, the message may have a delivery timeout
associated with it or the message destination may be deleted while the
message is in transit. Assuming delivery is possible, at some later date the
message reaches its destination and stays there until it is consumed (or

Copyright © 2001, DevelopMentor Inc. 679


Module 19: Java Messaging

discarded). Often the destination is persistent (its messages are held in


persistent storage ) so the producer and consumer may have different
(potentially non-overlapping) lifetimes. The consumer receives the message
from the destination at some later date, maybe long after the producer has
terminated. Optionally the consumer may send a response to the sender.
There are two common messaging models. 'Point-to-point' messaging is
illustrated in figure 19.3. One or more producers can send messages to a queue
and one or more consumers can receiving messages from the queue. A queue is
just an ordered holding area for messages. Even though many receivers can
listen for incoming messages on a queue, only a single receiver gets to actually
receive and process each sent message. It is up to the messaging system to
interleave the receive operations for multiple listeners in the appropriate way.
'Publish-and-subscribe' messaging is shown in figure 19.4. One or more
producers can publish a message to a topic. A topic is more like a message
broker and distributes the message to all receivers that have subscribed to the
topic (registered an interest in the topic's messages). A topic typically supports
transient and/or durable subscriptions. If a consumer registers a transient
subscription then it only receives messages while actively connected to the
topic. If the consumer disconnects and re-connects then all intervening
messages are lost. If a consumer registers a durable subscription it works like a
transient subscription while the consumer is actively connected to the topic.
However, if the consumer disconnect then all subsequent messages are stored
so that they can be read when the consumer next re-connects to the topic.

sender receiver

Message Message Message Queue receiver

sender receiver
Figure 19.3: Point-to-point messaging

680 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

durable subscriber
publisher (attached)

transient subscriber
Topic
Message Message Message (detached)

transient subscriber
publisher (attached)

durable subscriber
(detached)
Delivered at
re-attachment

Figure 19.4: Publish-and-subscribe messaging

Stripping away the layers of RPC reveals messages as first class citizens.
Messaging allows us to build naturally asynchronous systems where it is easy to
use more advanced delivery techniques such as fire-and-forget, multicast and
publish/subscribe. RPC is generally tied to the standard request/response
model.
Destinations give us the ability to completely decouple the producer of a
message from the consumer of a message. The producer doesn't know who the
consumer will be because it delivers the message to a destination and not
directly to another application. Applications may choose to subscribe to a topic
or listen on a queue and receive those messages. That means applications can
be dynamically coupled together resulting in a more flexible system. For
instance, a consumer and producer don't need to have overlapping lifetimes,
which makes it easy to build disconnected systems. Load-balancing is fairly
straightforward when multiple producers can deliver request messages to a
destination and multiple consumers can receive them. Producers and
consumers can work at their own rate without getting swamped or held up.
A central messaging system deals with all the details of reliably delivering
messages to wherever they have to go. Messaging systems will route and filter
messages based on their headers (possibly even content) which means that
application software doesn't have to. Messages are delivered with some quality
of service so it is possible to guarantee that a message is delivered and with at-
most-once semantics. It is also possible to send and receive messages as part of
a transaction. This means that it is possible to produce a group of related
messages or none at all and consume a group of related messages or none at
all. Additionally it enables messages to be produced and consumed as part of a

Copyright © 2001, DevelopMentor Inc. 681


Module 19: Java Messaging

larger transaction. With some care it is possible to build fully reliable (perhaps
even fully transacted!) communication between two parties. A maximum age
can be associated with a message, which is subsequently removed from the
system when the timeout expires. Messages can be given a higher priority to
hasten their movement through the system and ensure their delivery before
messages of lower priority, even those sent earlier. Reliable or transacted or
deadline-based or prioritized delivery is hard to achieve with RPC.
However, more power equals less simplicity. The reality is that message-
driven systems are often harder to code because programming asynchronous
systems where order is hard to predict is more challenging than programming
synchronous systems where the order can be forced. Communication is no
longer hidden from the developer who must deal with coordinating the sending
and receiving of messages.

682 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

Java Messaging Service


There are many different messaging systems
available offering similar facilities. JMS distils the
essentials of a messaging and exposes client and
provider APIs for Java.

Copyright © 2001, DevelopMentor Inc. 683


Module 19: Java Messaging

JMS Features
JMS defines framework to capture essence of messaging

• Synchronous or asynchronous operation


• Loosely- or strongly-coupled operation
• Point-to-point and publish-and-subscribe
• Guaranteed or fast delivery
• Transacted send/receive
• Prioritized delivery
• Deadline-based delivery
• Delivery filtering

684 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

There are may different messaging systems in the public domain. Examples are
MQSeries from IBM, MSMQ from Microsoft and Fiorano Software's FioranoMQ.
Java Messaging Service (JMS) attempts to capture the common essence of all
these systems by defining a common framework to address, send and receive
messages in an asynchronous fashion. Like JDBC, JMS is an interface-based
specification - JMS providers implement the interfaces and JMS clients use
them.
JMS supports both the point-to-point and publish-subscribe delivery models.
A JMS provider can implement either or both. The publish-and-subscribe model
allows for both durable and non-durable subscriptions. JMS allows applications
to be as loosely- or tightly-coupled as desired, ranging from asynchronous fire-
and-forget semantics to synchronous request-reply semantics.
JMS allows messages to be sent quickly or reliably. When they are sent
quickly no persistent logging of the message is performed as it hops around the
network bound for its destination so it could get lost. With reliable message
transmission the message is logged so it can never get lost but this slows down
transmission time. Messages are NEVER duplicated in either mode. This would
be unacceptable if the message contents implied some operation that was non-
idempotent.
Messages can also be sent and received under both local and global
transactions. This allows groups of messages to be sent and received atomically
and allows message send/receive operations to succeed or fail as part of a
larger transaction. Sent messages are not transmitted until the transaction
commits and are discarded if it aborts. Received messages are acknowledged
and discarded if the transaction commits or returned to the destination if the
transaction aborts.
Messages can be given a 'time-to-live'. Any message whose time-to-live time
expires before the message can be delivered will be destroyed. Messages can
also be given a priority. The JMS implementation does its best to deliver higher
priority messages before lower priority messages.
Normally a message gets delivered to its supplied destination. JMS also
defines a filter mechanism that allows consumers to fine tune message
selection. The consumer constructs an SQL-like statement to select messages
based on their properties. The JMS implementation only returns to the
consumer those messages that comply to the select criteria.

Copyright © 2001, DevelopMentor Inc. 685


Module 19: Java Messaging

JMS programming model


Interface-based with variations for ptp and pas

• JNDI Administered objects (factories and destinations) obtained via JNDI


• Connections represent physical connection to provider
• Sessions are single threaded context for producing/consuming messages
• Producers, consumers based on destination

686 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

Figure 19.5 illustrates the JMS objects and their relationships.


Administered Objects found via JNDI but created and
ConnectionFactory configured via a provider-specific technique

creates
MessageProducer
Connection
produce
creates creates based on

Session Destination Message

creates based on async consume


sync consume
(callback)
(polling)
MessageConsumer
async MessageListener
consume
(callback)

Figure 19.5: JMS object model

In order to talk to use a JMS implementation the programmer must first obtain
a connection to it. This connection is obtained via a connection factory. A
connection factory represents a set of connection configuration parameters
that have been defined by an administrator to correspond to a particular JMS
implementation. JMS says nothing about the administration model for
connection factories or the configuration data they define- it is totally specific
to a given JMS provider. See your local documentation for details. All the JMS
specification recommends is that the connection factory is obtained
programmatically by performing a JNDI lookup. Each connection factory is an
instance of either the QueueConnectionFactory or the
TopicConnectionFactory interface depending on whether the factory was
configured for point-to-point or publish-and-subscribe operation. Each
corresponding connection is of type QueueConnection or
TopicConnection. Here is an example of how to obtain a
QueueConnectionFactory from a JNDI lookup and then use it to create a
QueueConnection. The code for obtaining a TopicConnection from a
TopicConnectionFactory is very similar.
private QueueConnection getQueueConnection(String name)
throws NamingException, JMSException {
Context ctx = new InitialContext();
QueueConnectionFactory qfactory =
(QueueConnectionFactory)ctx.lookup(name);
return qfactory.createQueueConnection();
}

Copyright © 2001, DevelopMentor Inc. 687


Module 19: Java Messaging

The connection represents a physical connection to the provider, for


example a TCP connection. It, in turn, is the factory for a session. The session
is a single threaded context for producing and/or consuming messages and
scopes the boundaries of local transactions used to so. Again there are two
flavours of session, QueueSession and TopicSession. The following session
is created so that message producers/consumers created by this session will
not send/receive messages under a local transaction and messages will be
automatically acknowledgement once received. Transactions and message
acknowledgement options are covered later.
String qfname = "jms/MyQueueConnectionFactory";
QueueConnection qcon = getQueueConnection(qfname);
boolean tx = false;
int ackmode = Session.AUTO_ACKNOWLEDGE;
qsess = qcon.createQueueSession(tx,ackmode);

The session is used to create producers and consumers. A producer is used to


send messages to a destination and a consumer is used to receive messages
from a destination. A destination is the target of produced messages and/or
the source of consumed messages. It is also an administered object located via
JNDI and, again, the JMS specification says nothing about how they are
administered. Each destination is an instance of either the Queue or the
Topic interface depending on whether the destination was configured for
point-to-point or publish-and-subscribe operation. Here is an example of how
to obtain a Queue reference. The code to obtain a Topic reference is very
similar.
private Queue getQueue(String name)
throws NamingException, JMSException {
Context ctx = new InitialContext();
return (Queue)ctx.lookup(name);
}

Likewise, a producer implements either the QueueSender or


TopicPublisher interface and the consumer implements either the
QueueReceiver or TopicSubscriber interface depending on whether they
are based on a Queue or a Topic destination. Here is the code to create a
producer for a queue.
Queue queue = getQueue("jms/MyQueue");

688 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

qsender = qsess.createSender(queue);

Messages implement one of a number of interfaces all deriving from a


common base Message interface and they can be received synchronously or
asynchronously. Figure 19.6 puts it all together in one place. Notice how the
connection is initially in 'stopped' mode while everything is set up so that
clients don't need to deal with arrival of messages before they are ready.

String qfname = "jms/MyQueueConnectionFactory";


String qname = "jms/MyQueue";
Context ctx = new InitialContext();
QueueConnectionFactory qfac;
qfac = (QueueConnectionFactory)ctx.lookup(qfname);
QueueConnection qcon = qfac.createQueueConnection();
QueueSession qsess;
boolean tx = false; int ackmode = Session.AUTO_ACKNOWLEDGE;
qsess = qcon.createQueueSession(tx, ackmode);
Queue q = (Queue)ctx.lookup(qname);
QueueSender qsen = qsess.createSender(q);
QueueReceiver qrcv = qsess.createReceiver(q);
qcon.start();
Figure 19.6: Setting up to send/receive ptp messages

Copyright © 2001, DevelopMentor Inc. 689


Module 19: Java Messaging

Working with messages


Message=headers+properties+body

• Pre-defined headers contain routing/delivery information


• Optional properties allow application- or JMS-defined extensions
• Different body types for primitive stream, primitive map, object, text, byte
stream
• Messages can be sent with QOS, priority and time-to-live
• Messages can be received synchronously or asynchronously
• Message selectors fine-tune delivery
• Request/response semantics supported
• Non-transacted session sets message ack-ing strategy at creation
• Can peek into a queue with QueueBrowser

690 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

JMS messages are made up from headers, properties and a body. The headers
comprise information used primarily by the JMS implementation to route and
deliver the message. Figure 19.7 summarizes the meaning of the message
headers and when the by are set. Notice that some header values are set by
the application before the message is sent, some are set by the application as
the message is sent and some are set by the JMS implementation as the
message is sent.
Name Meaning Set by
JMSDestination Message destination. Destination that MessageProducer was
based on
JMSDeliveryMode NON-PERSISTENT (not reliable, at most once, Specified in MessageProducer
faster). send/publish method
PERSISTENT (reliable, only once, slower).
JMSExpiration Message expiry in ms at send time. 0 means no Specified in MessageProducer
expiry. System silently removes. send/publish method
JMSPriority How quickly it gets where it’s going. Specified in MessageProducer
0 – 4 (normal), 5 – 9 (expedited). send/publish method

JMSTimestamp Time message was sent/published. Not the time MessageProducer send/publish method.
it was actually transmitted

JMSCorrelationID Used to link messages together. Application- Specified before MessageProducer


specific. send/publish method called.

JMSReplyTo Used to specify a response destination if one is Specified before MessageProducer


required. Response is not mandatory. send/publish method called.

JMSType Message type identifier. Could be used as key Specified before MessageProducer
to the message definition in some type send/publish method called.
repository.
JMSRedelivered Message has been redelivered and may have Set by provider.
been seen before.

JMSMessageID Unique id Format of “ID:xxx”. Specified by and Generated by provider when


limited to one provider. MessageProducer send/publish method
called

Figure 19.7: JMS message headers

Properties are optional name, value pairs that allow the header information to
be extended either by the application or by the JMS implementation itself.
JMS-defined properties have reserved names. Some can be set by the
application before the message is sent, for instance, JMSXGroupID defines the
start of a message group and JMSXGroupSeq defines the sequence number of
the message within the group. Some are set by the provider on message send
such as JMSXUserID to define the sending user. Some are set by the provider
on message receive such as JMSXDeliveryCount revealing how many times
this message has been re-delivered. Other properties are application-defined.
Properties values must be set before the message is sent with any of the
Message.setXXXProperty() methods and once a message has been
consumed its properties values can be retrieved with any of the
Message.getXXXProperty() methods or property names iterated over with
Message.getPropertyNames().

Copyright © 2001, DevelopMentor Inc. 691


Module 19: Java Messaging

The message body defines the payload or data of the message and several
different body types are supported. A message implements a different
interface for each body type, all of which derive from the common base
Message interface. StreamMessage is a stream of Java primitives, written
and read sequentially in same order, MapMessage is a set of value (String),
name (Java primitive) pairs, written and read in any order, ObjectMessage is
a serializable object, TextMessage is a text string and ByteMessage is an
un-interpreted stream of bytes. The session is the factory for each of the
different message types. Figure 19.8 shows a variety of point-to-point message
sends. The previous code to establish qsess and qsen has been assumed.

...
byte[ ] data;
...
ByteMessage bm = qsess.createByteMessage();
bm.writeBytes(data);
int priority = 0; long timetolive=0;
qsen.send(bm, DeliveryMode.PERSISTENT, priority,
timetolive);

TextMessage tm = qsess.createTextMessage();
tm.setText("hello");
priority = 9; timetolive=10*1000;
qsen.send(tm, DeliveryMode.NON-PERSISTENT, priority,
timetolive);

MyObject obj = new MyObject("foo", 7, 2.5)


ObjectMessage om = qsess.createObjectMessage();
om.setObject(obj);
qsen.send(om);

StreamMessage sm = qsess.createStreamMessage();
sm.writeString("foo"); sm.writeInt(7);sm.writeDouble(2.5);
qsen.send(sm);

MapMessage mm = qsess.createMapMessage();
mm.setInt("num1", 7); mm.setString("name", "foo");
mm.setDouble("num2", 2.5);
qsen.send(mm);
Figure 19.8: Sending ptp messages with different bodies

There are a number of things to notice here. First, JMS supports two modes of
delivery. Non-persistent delivery means messages are not persistently stored as
they hop around the network bound for their destination. These are faster to
send but messages may be lost on failure. This provides at-most-once delivery
semantics. Persistent delivery means that messages are persistently stored as

692 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

they work their way around the network. They are slower to send but messages
won't be lost on failure. This provides once-and-only-once delivery semantics.
Second, some messages must be processed within a certain time frame else
they are useless. It is possible to set an expiry time, in ms, when the message
is sent. On expiry the message will be silently removed from the system. A
timeout of zero means the message will never expire. Last, messages may be
given a priority from 0-9 and this affects message delivery order. The provider
expedites the delivery of higher priority messages so it is possible that a
messages sent later with a higher priority may arrive ahead of those sent
earlier with a lower priority.
Messages can be received synchronously as in figure 19.9 or asynchronously
as in figure 19.10. A synchronous message consumer will block if there are no
messages waiting at the destination. For this reason there is an alternative
version of receive() that accepts a timeout parameter defining the
maximum time a receiver will block if there are no messages in the queue.
Note that with the asynchronous message consumption the OnMessage method
must handle all exceptions as it is considered a programming error to allow
exceptions to be thrown back from this method to the JMS provider. What is
the provider expected to do? It's not as if the application that produced the
message will get to field the exception. Handling an exception may involve
storing the message in an application-defined 'un-processable' destination or
producing a response message to go back to the originator of the message (if
they supplied a destination to reply to).

...
while (true) {
Message m = qrcv.receive();
if (m instanceof ByteMessage) {
byte data [];
int len = ((ByteMessage)m).readBytes(data);
} else if (m instanceof TextMessage) {
StringBuffer sb = ((TextMessage)m).getText();
} else if (m instanceof ObjectMessage) {
MyObject obj = new MyObject();
obj = ((ObjectMessage)m).getObject();
String s = obj.getFoo(); int i = obj.getNum();
}
}
...
Figure 19.9: Receiving ptp messages synchronously

Copyright © 2001, DevelopMentor Inc. 693


Module 19: Java Messaging

...
qrcv.setMessageListener(new MyListener());
qcon.start();
...
class MyListener implements MessageListener {
public void onMessage(Message m) {
try {
if (m instanceof StreamMessage) {
StringBuffer s = m.readString();
int n = m.readInt();
double d = m.readDouble();
} else if (m instanceof MapMessage) {
double d = m.getDouble("num2");
StringBuffer s = m.getString("name");
int n = m.getInt("num1");
}
} catch (Throwable t) {
// Divert message to poison queue?
}
}
}
Figure 19.10: Receiving ptp messages asynchronously

Sessions (and therefore the producers and consumers created by the session) do
not support concurrent access, i.e. they are intended to be used by a single-
thread at a time. This is partly so that message consumers and producers are
not forced to be thread-safe. To support this, the session serializes the
execution of all its message listeners. This does mean that for a given session
messages must be consumed either synchronously or asynchronously but not
both. If concurrent message production or consumption is required then either
use multiple sessions or synchronize multiple threads to a single session
yourself. If multiple sessions have concurrent subscribers to same topic, they
all get the message. If multiple sessions have concurrent receivers from the
same queue then the delivery semantics are undefined.
Messages may get lost but messages should never be duplicated as they may
represent non-idempotent operations. For this reason the session holds onto
messages that have been consumed until they are acknowledged.
Acknowledged messages are then forgotten and never redelivered.
Unacknowledged messages get recovered and re-delivered with the
JMSRedelivery header field set. Due to features like message priority and
expiry it is possible that the order of redelivery may change. The details of
exactly how message acknowledgement works depends on whether the session
is transacted or not. Message acknowledgement and recovery is automatic for a
receive from a transacted session as will be seen later. For a non-transacted
session the acknowledgement and recovery strategy can be set at session

694 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

create time. There are 3 modes each of which can be specified as the second
parameter to QueueConnection.createQueueSession() or
TopicConnection.createTopicSession(). The
Session.AUTO_ACKNOWLEDGE parameter means that the session
automatically acknowledges the receipt of a message either when the call to
MessageConsumer.receive() returns successfully or when the
MessageListener.onMessage() returns successfully. The
Session.CLIENT_ACKNOWLEDGE parameter means that the application must
acknowledge a message by calling the Message.acknowledge().
Acknowledging any message automatically acknowledges all unacknowledged
messages that have been delivered by the session up to the consumption of the
acknowledged message. This effectively enables applications to consume a
group of messages together and thus implement their own transaction
semantics. Finally the Session.DUPS_OK_ACKNOWLEDGE parameter instructs
the session that it can lazily acknowledge messages. This is appropriate for
applications that can deal with duplicate messages because the session does
not need to work so hard to avoid them. Any such duplicate messages will be
delivered with the JMSRedelivered header set. Calling the session's
recover() method at any time will re-start delivery from the first
unacknowledged message.
When creating a consumer, a message selector expression can be supplied.
This tells the system to filter messages and deliver only those that satisfy the
message selection criteria. Any messages that does not satisfy the message
selection criteria stays at the destination until a less selective consumer tries
to read it or it expires. The conditional selector string is based on a subset of
SQL92. The only parts of the message that can be used in the selector string
are a subset of the message headers and any message property - the message
body cannot be used. Figure 19.11 shows a simple example.

Copyright © 2001, DevelopMentor Inc. 695


Module 19: Java Messaging

// Sender code
...
TextMessage tm = qsess.createTextMessage();
tm.setText("hello");
tm.setStringProperty("name", "fred");
qsen.send(tm);
...

// Receiver code
...
String selector="name='fred'"
QueueReceiver qrcv = qsess.createReceiver(q,selector);
TextMessage tm = (TextMessage)qrcv.receive();
// Will only get messages with property "name" set to
"fred"
StringBuffer data = tm.getText();
...
Figure 19.11: Message selector

JMS supports return address style delivery. This involves the sender creating a
temporary destination and then setting it as the value of the JMSReplyTo
message header before sending the message. Figure 19.12 illustrates.

// Sender code
...
TextMessage tm = qs.createTextMessage();
m.setText("hello");
TemporaryQueue replyq = qsess.createTemporaryQueue();
QueueReceiver replyrcv = qsess.createReceiver(replyq);
tm.setJMSReplyTo(replyq);
qsen.send(tm);
replyrcv.receive(); // Could have done async receive
...

//Receiver code
...
TextMessage tm = (TextMessage)qrcv.receive();
Queue replyq = tm.getJMSReplyTo();
QueueSender replysen = qsess.createSender(replyq);
TextMessage tmreply = qsess.createTextMessage();
tmreply.setText(tm.getText()+" to you too");
replysen.send(tmreply);
...
Figure 19.12: Return-address style delivery

696 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

An even simpler way to do this for synchronous request/response is to use a


QueueRequester which takes a QueueSession and destination Queue as
construction parameters and cooks up a temporary response Queue on the fly.
QueueRequester.request() takes the request Message and waits for
response Message, which it returns. This is shown in figure 19.13.

...
QueueRequester qreq = new QueueRequester(qsess,q);
TextMessage tmin = qsess.createTextMessage();
tmin.setText("hello");
TextMessage tmout = qreq.request(tmin);
...
Figure 19.13: Simple synchronous return-address style delivery

It is also possible to browse a queue (with a selector if desired) and peek at the
messages in the queue without removing them. Session.createBrowser()
yields a QueueBrowser that provides an Enumeration. The state of the queue
might change while browsing as JMS doesn't mandate a snapshot and so changes
may or may not be visible.

Copyright © 2001, DevelopMentor Inc. 697


Module 19: Java Messaging

Transactions
Can group messages into atomic units

• All messages consumed/produced or none are


• Transacted session scopes local 'chained' TXs
• Specified at session create time
• Session may enlist on global TXs
• Commit: messages stay produced/consumed, consumed messages
acknowledged
• Abort: produced messages discarded, consumed messages recovered
• Note - TX does not flow from sender to receiver

698 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

It is sometime useful to be able to group together messages and produce or


consume them as an atomic unit, i.e. all messages get produced/consumed or
none do. The session scopes local transactions for just this purpose. A session
can be marked as transacted at creation time and this provides a 'chained'
transaction mode where local transactions are silently started when needed
and all message operations for the session are part of a local transaction.
Figure 19.14 shows how to create a transacted session and send messages
under a transaction.

...
boolean tx = true; int ackmode = Session.AUTO_ACKNOWLEDGE;
QueueSession qsess = qcon.createQueueSession(tx, ackmode);
...
TextMessage tm = qsess.createTextMessage();
tm.setText("hello");
qsen.send(tm);
tm = qsess.createTextMessage(); tm.setText("world");
qsen.send(tm);
...
qsess.commit(); // Both messages actually sent here
// Calling qsess.abort() here would discard both messages
...
Figure 19.14: Sending ptp messages under a local TX

When messages are produced as part of a transaction they are held until the
transaction ends. If the transaction commits they are sent/published and if not
they are destroyed, never to be seen. When messages are consumed as part of
a transaction they are removed immediately from the destination and seen by
the consuming application but not acknowledged. If the transaction commits
then the messages are acknowledged. If the transaction aborts then the
messages are not acknowledged but recovered and put back in the destination
to be re-delivered at a later date. Note that a transaction used to send a
message does not flow to the receiver - a message sent under one transaction
is received under another transaction (if it is received under a transaction at
all). If transacted communication is required between two parties then some
additional application-level protocol must be designed to achieve this.
Local transactions are scoped to a session within a particular JMS provider.
They cannot be used to atomically manipulate resources held in other resource
managers, such as data in a database. In order to be able to produce and/or
consume messages and manipulate data in a database as part of the same
transaction then a global transaction is needed. When would a distributed
transaction actually be required when producing/consuming messages? Imagine
we have a transacted operation in the middle-tier that manipulates data in the
database. Perhaps certain independent steps in the operation must occur but
are not time critical, e.g. operation auditing or state change notification. In

Copyright © 2001, DevelopMentor Inc. 699


Module 19: Java Messaging

order to keep the transaction time short those steps could be removed from
the critical code path and completed asynchronously after the transaction
commits. One way to achieve this would be to send messages encoded with the
details of these steps as part of a distributed transaction. This guarantees that
the messages are sent if the transaction commits and are not sent if the
transaction aborts. JMS doesn't require a provider to support distributed
transactions but if it does it must be a JTA wrapped XA transaction. The
programming model is similar to that used for JDBC. A JMS
XAConnectionFactory creates an XAConnection which creates an
XASession whose XAResource is used to enlist the session onto a distributed
transaction. In this mode the session's commit() and rollback() methods
throw an exception if used as part of a distributed transaction. It is actually
more likely for the JMS provider to be built into an application server that
supports distributed transactions and have the session silently auto-enlisted
onto an EJB managed transaction.

700 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

EJB Messaging-driven Beans


There was no JMS story for EJB 1.1 so integrating
EJB with messaging was a challenge. EJB 2.0
application servers have built-in JMS support and
provide listeners that execute EJB code whenever a
message is received - message-driven beans.

Copyright © 2001, DevelopMentor Inc. 701


Module 19: Java Messaging

EJB 2.0/JMS integration


EJB 2.0 spec mandates JMS integration

• JMS connection factories and destinations are managed resources


• Can produce message under EJB managed TX
• Can consume message within EJB message-driven bean
• A MessageListener component
• Has no remote or home interface
• Executes in response to client sending message

702 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

EJB 1.x defined no model for asynchronous programming. If an EJB 1.1 server
had JMS support then any attempt to integrate EJB and messaging was, at best,
a hack. The EJB 2.0 specification mandates JMS integration and so EJB 2.0
application servers now have their own JMS implementation built-in. JMS
connection factories and destinations are managed resources available to
Servlet, JSP or EJB code via JNDI, just like JDBC connections are. This means,
for instance, that an EJB session bean can produce messages under an EJB
managed transaction.
But what we really want to do is execute an EJB component in response to a
message being received and have it operate on the message. Optionally we
might like to execute the EJB code under the same transaction that was used
to consume the message. Enter EJB message-driven beans. An EJB message-
driven bean is a component-based JMS listener that camps out on a particular
destination waiting for messages to arrive. It behaves very much like an EJB
stateless session only it is called by a client asynchronously sending a message
to a destination rather than a client locating the bean's home, creating it and
calling it. The container performs all the low-level JMS grunge and all the
developer has to do is write the listener and provide a deployment descriptor
that describes its attributes. Figure 19.15 shows how it hangs together.

client ConnectionFactory
ejb container

Connection

Session

MessageConsumer
Sends/ context
sets
publishe s (run-time
Destination
environment)

MessageListener EJB object bean


delivers

defines service s to calls platform code


container construct interposer
generated
deployment system
developer services
descriptor
defined

Figure 19.15: EJB interposition model for message-driven bean

Copyright © 2001, DevelopMentor Inc. 703


Module 19: Java Messaging

Coding a message-driven bean


Like a stateless session (with caveats for asynchronous invocation) but
simpler

• No home or remote interface


• Implements MessageDrivenBean and MessageListener
• Normal onMessage() rules apply
• Has no direct caller but can run in specified security context
• Can be CMT root (TX=Required, TX=NotSupported) or use BMT
• Message dequeued under CMT but not BMT
• Message ack-ing always handled by container

704 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

The message-driven bean has no remote or home interface. The way to execute
it is to send a message to the destination it is configured to listen on. The bean
class itself must implement the javax.ejb.MessageDrivenBean interface
and the javax.jms.MessageListener interface. Figure 19.16 shows a
typical bean class implementation. As usual all exceptions should be handled
by the onMessage() method. If not then the container will abort the bean's
transaction if it has one and destroy the bean instance.
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.jms.MessageListener;
import javax.jms.Message;

public class TellerMessageDrivenBean


implements MessageDrivenBean, MessageListener {
// No arg ejbCreate() like a stateless session
public void ejbCreate() {...}
// Method signatures mandated by MessageDrivenBean
interface
public void ejbRemove() {...}
public void setMessageDrivenContext(MessageDrivenContext
ctx) {...}
// Method signature mandated by MessageListener interface
public void onMessage(Message m) {
// Handle message in here
...
}
}
Figure 19.16: Bean class for a message driven bean

The beans context is provided to it at create time as usual. Even though


javax.ejb.MessageDrivenContext is derived from
javax.ejb.EJBContext many of its methods are not accessible because
they don't make sense in the context of an asynchronous process and the
container will throw an IllegalStateException if they are called. For instance,
getCallerPrincipal and isCallerInRole are unavailable because the
client security context isn't propagated with the message that caused the
message-driven bean to execute. The getEJBHome can't be called as message-
driven beans have no EJB home object.
The deployment descriptor is pretty straightforward and an example is
shown in figure 19.17. Notice the descriptor contains all the information except
the destination name required to deploy the message-driven bean. This is set in
an application server's vendor-specific configuration file. It is possible to
specify whether the bean is intended to listen on a topic or a queue and, if a
topic, whether the bean should act as a durable subscriber. Because message-

Copyright © 2001, DevelopMentor Inc. 705


Module 19: Java Messaging

driven beans do not execute in the context of their authenticated caller, it is


possible to configure the message-driven to execute in a security context that
can be propagated to other downstream EJBs called during message processing.
<ejb-jar>
...
<enterprise-beans>
<message-driven>
...
<ejb-class>TellerMessageDrivenBean </ejb-class>
<transaction-type>Bean</transaction-type>
<acknowledge-mode>Auto-acknowledge</acknowledge-mode>
<message-driven-destination>
<!-- Notice destination name not held here! -->
<destination-type>javax.jms.Queue</destination-
type>
</message-driven-destination>
<security-identity>
<description></description>
<run-as-specified-identity>
<description></description>
<role-name></role-name>
</run-as-specified-identity>
</security-identity>
</message-driven>
</enterprise-beans>
</ejb-jar>
Figure 19.17: Deployment descriptor for a message driven bean

Message-driven beans can take part in EJB managed transactions. Transactions


cannot be propagated with a JMS message so message-driven beans can only be
the root of a container-managed transaction or start a bean-managed
transaction. Only the Required and NotSupported container-managed
transaction attributes may be set for the onMessage() method. Container-
managed transactions work as described in an earlier section with the bean
running under the same transaction that was used to consume the message. If
the container-managed transaction aborts then the message is recovered and
re-delivered. Bean-managed transactions work as described earlier too but of
course because the bean starts the transaction after the message is consumed
then the message was not consumed under the transaction. The bean-managed
transactions must end before returning from the onMessage() method.
The message acknowledgement mode can be set if the bean has no
container-managed transaction. It can only be set to DUPS_OK_ACKNOWLEDGE
or AUTO_ACKNOWLEDGE as the container always handles message
acknowledgement for message-driven beans and it is illegal for the bean to use
CLIENT_ACKNOWLEDGE.

706 Copyright © 2001, DevelopMentor Inc.


Module 19: Java Messaging

As mentioned above, message-driven beans are really just stateless sessions


that are executed in response to a message arriving at a destination. Their
lifetime is completely dictated by the container and they are held in a pool
until needed. Figure 19.18 illustrates. Just like a stateless session they must
have a no-arg constructor and a no-arg ejbCreate() (although it cannot
declare exceptions in its throws clause as these could never be picked up by
the message sender). Because a message-driven bean instance is a listener it
does not have to be thread-safe. This is still true even if the EJB server decides
to use the "expert level" classes defined in the JMS specification to provide a
mode of operation that allows multiple messages to be handled concurrently by
separate bean instances.
container creates when needed:
Class.newInstance()
setMessageDrivenContext()
ejbCreate()
does not in pool (no identity)
exist waiting to execute onMessage()
container destroys:
ejbRemove()
Object.finalize()
onMessage() message arrives at
execution destination,
ends onMessage()
executes
Executing onMessage() on
behalf of some client
sending a message

Figure 19.18: Lifecycle of a message-driven bean

Copyright © 2001, DevelopMentor Inc. 707


Module 19: Java Messaging

Summary
• The needs of large scale systems are not always met by RPC
• Messaging provide asynchronous, decoupled operation
• JMS spec distils the essence of messaging systems
• JMS has reliability features such as persistent messages, transactions and
durable subscriptions
• JMS supports flexible delivery mechanisms such as deadline-based and
prioritized delivery
• JMS and EJB 2.0 are well integrated
• EJB 2.0 message-driven beans are component-based listeners

708 Copyright © 2001, DevelopMentor Inc.


Module 20

What's New

Copyright © 2001, DevelopMentor Inc. 709


Upcoming in the Servlets 2.3 JSP 1.2 Specification

After completing this module, you should be able to:


 explain the structure of Filters in Web Applications
 understand Filters and how they are used
 understand Filter chains Request and Response Wrappers
 understand Listeners and the Event Model
 understand The new JSP Validation model

710 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

New Features in JSP 1.2


The JSP 1.2 Specification introduces a whole new set
of features, including validation of the JSP page
before compilation.

Copyright © 2001, DevelopMentor Inc. 711


Module 20: What's New

Validation
Page may be validated when first compiled

• Check that tag has valid attribute


• Check that tag has valid children
• TagLibraryValidator class added to Tag Library
• Page passed in its XML representation as a PageData object

712 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

While the custom action (Tag) mechanism of JSP has some built in validation,
this is limited in what it can achieve. For example the page compiler can check
that the all the "required" attributes are defined and that the user hasn't set
any attribute the tag is not expecting. However the compiler cannot check that
the attribute values are of the right type (the whole page is text) or that the
values are in the correct range, this can only be done by the tag author. In the
JSP 1.2 release a tag author can specify that she wants to validate tag. This is
done by creating a class that implements
javax.servlet.jsp.tagext.TagLibraryValidator and specifying this
class's availability through the TLD.
The validator is executed when the page is first compiled (and only then).
Validators have a lifecycle: setInitParameters are called to initialise the
validator; then its validate method is called. Eventually the container calls
release to let the validator know it's done. The validate method may be
called many times if this validator is to be used for many tags.
The validate method is passed the prefix the tag is using, the URI from the
taglib directive, and a PageData object. The PageData object gives the
validator access to an InputStream through which the validator can read the
page in XML format. The validate method returns null for success or an
array of ValidationMessage objects if the page isn't valid. Each object
contains a validation message, and if the tag has an id attribute the value of
that attribute.
You make the validator available by adding a validator entry to the tag's
TLD.

Copyright © 2001, DevelopMentor Inc. 713


Module 20: What's New

Listeners
Tag may be a listener

• Written the same way as standard event listeners


• Packaged as tags
• Add "listener" element to TLD

714 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

Simply a repackage of standard servlet listeners as tags. The listener is made


available as a tag by adding a listener element to the TLD, and the tag
implements the appropriate listener interface.

Copyright © 2001, DevelopMentor Inc. 715


Module 20: What's New

Better tag lib support


Tag Libraries have been tidied up

• TLD Elements to avoid TEI


• <!ELEMENT variable ( (name-given | name-from-attribute),
variable-class?, declare?, scope?) >
• TLD Elements for icons, descriptions etc.

716 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

Currently if a tag author wants to be able to validate the attributes passed to


the tag, the author has to supply a TagExtraInfo class. In JSP 1.2 it is
possible to specify the validation in the TLD by adding a variable element to
the tag element. The variable element specifies the tag's name, class and
scope, just as the TagExtraInfo would. It is an error to have both a
variable element and a TagExtraInfo for the same tag.

Copyright © 2001, DevelopMentor Inc. 717


Module 20: What's New

Property Verification
Bean PropertyEditor can validate property

• Bean can have an associated PropertyEditor


• setAsText is then called
• Method can throw an IllegalArgumentException

718 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

It is now possible to specify a PropertyEditor for a bean so that when a


container tries to set the property of the bean, the property editor's
setAsText method is called. This allows the bean to perform validation on
the property. If the property isn't valid, the setAsText method can throw an
IllegalArgumentException.

Copyright © 2001, DevelopMentor Inc. 719


Module 20: What's New

Using Events in a Java WebApplication


Resources in a web application often need access to
resources that need to be initialised at either
application start or session start, and freed when
the application or session ends. Events provide a
way to manage and initialise these resources

Copyright © 2001, DevelopMentor Inc. 721


Module 20: What's New

What are Listeners


Events are fired at users at appropriate times

• Application Events at app start/end


• Session Events at Session start/end
• Attribute events when attribute added/removed
• Listeners listen for events
• Follow JavaBeans Event model

722 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

In the current release of the Servlet and JSP specifications it is difficult if not
impossible to write code that can respond to Application or Session start and
end events. The Servlet 2.3 specification cures that omission by including the
concept of "listeners." A listener is code that executes in response to a specific
event. There are four listener types that correspond to eight events. The
listeners are ServletContextListener,
ServletContextAttributeListener,
HttpSessionActivationListener and
HttpSessionAttributeListener. They listen for: application start and
end; the addition and removal of attributes from an application; session start
and end; and the addition and removal of attributes from a session,
respectively. Listeners follow the standard Java Beans model for event
listeners, that is, they are registered with an event source (this is done by the
container) and, when an event is fired, the listener is called and passed an
object describing the event.

Copyright © 2001, DevelopMentor Inc. 723


Module 20: What's New

Writing Listeners
Listeners Implement Appropriate Interface

• ServletContextListener
• ServletContextAttributeListener
• HttpSessionActivationListener
• HttpSessionAttributeListener
• Passed appropriate "Event" object

724 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

Writing a listener is simply a matter of implementing the correct interface


(these are listed above). Figure 20.1 shows an example of an application
listener. The example implements
javax.servlet.ServletContextListener and will be called when the
application starts and when the application ends. The container will call the
contextInitialized method at application start-up and
contextDestroyed at application end. Notice that both methods are passed
a ServletContextEvent object. This gives the listener access to the
ServletContext.
public class WhitePagesServletListener
implements
javax.servlet.ServletContextListener
{
java.util.Hashtable whitePages;

public WhitePagesServletListener()
{
System.out.println("In ctor");
whitePages = new java.util.Hashtable();
}

public void contextDestroyed(ServletContextEvent sce)


{
}

public void contextInitialized(ServletContextEvent sce


)
{
sce.getServletContext().setAttribute("addrbook",
whitePages);
}
}
Figure 20.1: Application Listener

Once the listener has been written it has to be deployed. This is done by
copying the class into the correct location at the server, and telling the
container that the listener exists. To configure the listener an entry has to be
added to web.xml. This is shown in figure 20.2. You can have multiple listeners
deployed--they will be executed in the order in which they are listed in
web.xml.

Copyright © 2001, DevelopMentor Inc. 725


Module 20: What's New

<listener>
<listener-class>
com.develop.ewebjava.lab.WhitePagesServletListener
</listener-class>
</listener>
Figure 20.2: Configuring A Listener in the Deployment Descriptor

726 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

Using Filters in a Java WebApplication


An application often needs a way to provide a set of
services that are available throughout the
application and web applications are no different.
Filters allow us to provide those services, they are
called both before and after a resource has been
executed.

Copyright © 2001, DevelopMentor Inc. 727


Module 20: What's New

What is a Filter?
Filter sits between client and requested resource

• The resource could be a servlet/JSP/HTML etc.


• They are executed before/after the resource is executed
• Request/Response could be modified before/after being passed on
• Filters may be executed as part of a chain
• Can use filters to provide: Session management, logging, security, XML
transforms etc.

728 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

The Servlet 2.3 specification defines a new construct--the filter. A filter is a


piece of code that intercepts a request sent to a resource in a web application.
The filter can choose to pass the request on, in which case the request will be
forwarded to either the next filter in the filter chain, or to the requested
resource if this is the last filter in the chain. The filter also sees the response
before it is returned to the client. The figure 20.3 illustrates this
diagrammatically.

Servlet
client

Filter
Filter
Filter

Figure 20.3: Code Path to Servlet through filters

Copyright © 2001, DevelopMentor Inc. 729


Module 20: What's New

Writing Filters
Filter writers implement javax.servlet.Filter

• init(FilterConfig config) called once


• destroy() (may be) called once
• doFilter(request, response, chain) where the work is done
• doFilter() may "wrap" Request and/or Response
• Filter calls chain.doFilter(...)

730 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

All filters implement the javax.servlet.Filter interface. This interface


defines the lifecycle of a filter. The init method is called once when the
filter is loaded, and is passed a FilterConfig object. This object, like the
ServletConfig gives the filter access to any configuration parameters that
have been defined in the deployment descriptor. Figure 20.4 shows how a filter
can access the ServletContext through the FilterConfig object.
public void init(FilterConfig filterConfig)
{
fc = filterConfig;
if(fc != null)
{
ctx = fc.getServletContext();
// other initialisation
}
}
Figure 20.4: "init" Method

The filter also has a destroy method that will be called when the filter is
unloaded.
The most important method in the Filter interface is doFilter, this is
where the action takes place. The doFilter method is passed three
parameters, the Request, Response and a FilterChain instance. Figure
20.5 shows a "typical" doFilter implementation. Cast the request and
response to the "right" type, do some work and call chain.doFilter. The call
to chain.doFilter is optional, calling it causes the container to pass the
request down the filter chain. However it is perfectly reasonable for the filter
to handle the request itself, send a response back to the client, and return
without calling chain.doFilter, or the filter could execute another resource
by using a RequestDispatcher.

Copyright © 2001, DevelopMentor Inc. 731


Module 20: What's New

public void doFilter(ServletRequest req,


ServletResponse resp,
FilterChain chain)
throws java.io.IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;

// do work here

// optionally pass on request

chain.doFilter(req, response);
}
Figure 20.5: "doFilter" Method

Assuming the filter calls chain.doFilter what happens next? The call will
proceed down the filter chain and eventually return to this filter (i.e. the
chain.doFilter will return), at this point the filter can manipulate the
outgoing response.

732 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

Wrapping Request/Response
Possible to change Request and filter Response

• Filter may not want resource to see original request details


• Filter may want to change response
• Can create HttpServletRequestWrapper
• Can create HttpServletResponseWrapper

734 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

What if the filter doesn't want the down chain objects to see the original
request data, or the original request headers. Or suppose the filter wants to
"trap" the downstream output data or response headers. To do either of these
things the filter needs to create either a [Http]ServletRequestWrapper or
a [Http]ServletResponseWrapper. Figure 20.6 shows an
HttpServletRequestWrapper. In either wrapper it is possible to intercept
calls to the methods for manipulating and querying the headers, however
intercepting the response data writing is trickier. In that case the
ServletOutputStream and PrintWriter has to be replaced, and the calls to
HttpServletResponseWrapper.getWriter() and
HttpServletResponseWrapper.getOutputStream() overridden.
class SessionRequestWrapper extends
HttpServletRequestWrapper
{
SessionRequestWrapper(HttpServletRequest request)
{
super(request);
}
// Other code here
}
Figure 20.6: Creating a Request Wrapper

Copyright © 2001, DevelopMentor Inc. 735


Module 20: What's New

Filter Configuration
Filter Configures in Deployment Descriptor

• May be associated with a URL


• May be associated with a named resource

736 Copyright © 2001, DevelopMentor Inc.


Module 20: What's New

Figure 20.7 shows how a deployer configures filters. The filter can be
associated with either a "named" resource or with a URL pattern (i.e. a group
of resources)
<filter>
<filter-name>Sessions Filter</filter-name>
<filter-
class>com.develop.kevinj.sessions.FilterSession</filter-
class>
</filter>

<filter-mapping>
<filter-name>Sessions Filter</filter-name>
<url-pattern>/*</url-pattern>
<!-- <servlet-name>SessionTest</servlet-name> -->
</filter-mapping>
Figure 20.7: Example Filter Configuration

Copyright © 2001, DevelopMentor Inc. 737


Module 20: What's New

Summary
• Filters allow us to add services to Web applications
• Request Wrappers allow us to change the request data that a resource sees
• Response Wrappers allow us to filter responses before they are sent to the
client
• Listeners enable the initialisation and de-initialisation of resources
• JSP 1.2 has more flexible deployment options
• JSP 1.2 has a better validation model

738 Copyright © 2001, DevelopMentor Inc.


Glossary

Glossary

access controller central class in Java 2 security, where a concrete security


manager delegates work to the access controller
bootstrap class loader class loader that loads the system classes. Shows up as
null in programmatic interfaces
code source the URL and signer of a class
context class loader thread-specific class loader often used by factory
methods
Cookie An item of data sent between the client and server in an HTTP
transaction to allow the server to track a conversation with the client.
CRLF Carriage Return Line Feed
DOM Document Object Model
extensions class loader class loader that loads standard extensions, i.e. JAR
files installed to JRE/lib/ext
HTTP Hypertext Transfer Protocol
JAR Java ARchive file
javap Java decompiler, a command-line tool that ships with the Java SDK
JDBC Java Database Connectivity (Not!)
JMS Java Messaging Service
JNDI Java Naming and Directory Interface
MIME Multipart Internet Mail Extensions
MVC The Model View Controller Architecture. A way of creating applications
that keeps the two parts of User Interface and business logic separate.
permission class that represents some secured action
policy returns a set of permissions for a code source
policy file text file used to administer the policy reference implementation
privileged scope a scope in which the normal security checks up the call stack
are suspended
RPC Remote Procedure Call
SAX Simple API for XML
security manager choke point through which all secured operations pass
Servlet Server side Java code that follows a well known idiom for handling
client requests
SSL Secure Sockets Layer
system class loader class loader that loads from the classpath
TLS Transport Layer Security - the replacement for SSL
UDDI Universal Description, Discovery and Integration
Web Application Deployment Descriptor The web.xml file that holds the
declarative deployment information for this application

Copyright © 2001, DevelopMentor Inc. 739


Glossary

Web Service Programmable component accessible using standardized XML


messaging over an Internet protocol
WSDL Web Service Description Language
XML eXstensible Markup Language
XPath W3C Specification for addressing an XML document
XSLT Extensible Stylesheet Language: Transformations. An XML vocabulary for
expressing transformations.

740 Copyright © 2001, DevelopMentor Inc.


Bibliography

Bibliography

Web Sites
A New Era for Java Protocol Handlers:
http://developer.java.sun.com/developer/onlineTraining/protocolhandlers
Apache SOAP implementation: http://xml.apache.org/soap/index.html
AspectJ: http://www.aspectj.org
Debugging Class Loading:
http://developer.java.sun.com/developer/TechTips/2000/tt1128.html#tip2
DOM Level 2 Core Specification: http://www.w3.org/TR/2000/REC-DOM-Level-2-
Core-20001113/
Dynamic Proxies:
http://developer.java.sun.com/developer/TechTips/2000/tt0530.html
EJB Home Page: http://java.sun.com/products/ejb
EJB Interest List: http://archives.java.sun.com/ejb-interest.html
Home Page for UDDI Community: http://www.uddi.org
HTTP Authentication RFC: http://www.ietf.org/rfc/rfc2617.txt
HTTP RFC: http://www.ietf.org/rfc/rfc2616.txt
HTTP State Management Mechanism: http://www.ietf.org/rfc/rfc2109.txt
IBM DeveloperWorks Web Services Site:
http://www.ibm.com/developerworks/webservices/
java.security.Policy white paper:
http://www.javageeks.com/Papers/JavaPolicy/index.html
JMS Home Page: http://java.sun.com/products/jms/
JSP Home Page: http://java.sun.com/products/jsp
MIME: http://www.ietf.org/rfc/rfc2045.txt
MIME: http://www.ietf.org/rfc/rfc2046.txt
MIME: http://www.ietf.org/rfc/rfc2047.txt
MIME: http://www.ietf.org/rfc/rfc2048.txt
MIME: http://www.ietf.org/rfc/rfc2049.txt
MSDN UDDI Article: http://msdn.microsoft.com/xml/articles/xml12182000.asp
MSXML 3.0 from Microsoft:
http://download.microsoft.com/download/xml/Install/3.10/W98NT42KMe/EN-
US/msxml3sp1.EXE
Saxon processor from Michael Kay: http://users.iclway.co.uk/mhkay/saxon/
SecurityManager, Policies, and the Policy File:
http://developer.java.sun.com/developer/TechTips/2000/tt0926.html
The man who led the development effort for SAX: http://www.megginson.com
Understanding Class.forName():
http://www.javageeks.com/Papers/ClassForName/index.html
Using BootClasspath:
http://www.javageeks.com/Papers/BootClasspath/index.html

Copyright © 2001, DevelopMentor Inc. 741


Bibliography

Using Privileged Scopes:


developer.java.sun.com/developer/TechTips/2000/tt1128.html#tip1
W3C WSDL "Note": http://www.w3.org/TR/wsdl.html
Xalan processor from Apache: http://xml.apache.org/xalan-j/index.html
XML Information Set Candidate Recommendation: http://www.w3.org/TR/xml-
infoset/
XML Protocol Requirements Document: http://www.w3.org/TR/xmlp-reqs/
XML Schema Datatypes: http://www.w3.org/TR/xmlschema-2/
XML Schema Primer: http://www.w3.org/TR/xmlschema-0/
XML Schema Structures: http://www.w3.org/TR/xmlschema-1/
XPath Specification: http://www.w3.org/TR/xpath
XSL Transformations (XSLT) Version 1.0 Recommendation:
http://www.w3.org/TR/xslt
XT processor from James Clark: http://www.jclark.com/xml/xt.html

Books
Clinton Wong. 2000. Http Pocket Reference. Sebastapol CA: O'Reilly.
Marty Hall. 2000. Core Servlets and JavaServer Pages (JSP). USA: Prentice Hall.
Jason Hunter, William Crawford. 2001. Java Servlet Programming. Sebastapol
CA: O'Reilly.
Hans Bergsten. 2000. JavaServer pages. Sebastapol CA: O'Reilly.
Monson Haefel. 2000. Enterprise JavaBeans 2nd Edition. USA: O'Reilly.
Don Box, Aaron Skonnard, John Lam. 1999. Essential XML. Boston MA: Addison
Wesley Longman.
Brett McLaughlin. 2000. Java And XML. Sebastapol CA: O'Reilly.
Rosanna Lee, Scott Seligman. 2000. JNDI API Tutorial and Reference. USA:
Addison-Wesley.
Seth White, Maydene Fisher, Rick Cattell, Graham Hamilton, Mark Hapner.
1999. JDBC(TM) API Tutorial and Reference, Second Edition. USA: Addison-
Wesley.
Tim Ewald. 2001. Transactional COM+: Building Scalable Applications. Boston
MA: Addison Wesley Longman.
Jim Gray and Andreas Reuter. 1992. Transaction Processing: Concepts and
Techniques. San Francisco CA: Morgan Kaufmann Publishers.
Philip Bernstein and Eric Newcomer. 1997. Principles of Transaction Processing.
San Francisco CA: Morgan Kaufmann Publishers.
Allen Holub. 2000. Taming Java Threads. USA: APress.
Doug Lea . 1999. Concurrent Programming In Java. Boston MA: Addison Wesley
Longman.
Ted Neward. 2000. Server-Based Java Programming. Greenwich CT: Manning.
Bill Venners. 1999. Inside the Java Virtual Machine, 2nd Ed.. New York NY:
McGraw-Hill.
Krzysztof Czarnecki, Ulrich W. Eisenecker. 2000. Generative Programming.
Boston MA: Addison-Wesley.

742 Copyright © 2001, DevelopMentor Inc.


Bibliography

Bill Joy et al.. 2000. The Java Language Specification, 2nd Ed.. Boston MA:
Addison-Wesley.
Li Gong. 1999. Inside Java 2 Platform Security. Boston MA: Addison-Wesley.
Eric Rescorla. 2000. SSL and TLS. USA: Addison Wesley.
Schneier. 1996. Applied Cryptography. USA: Wiley.
Jonathan Knudsen. 1998. Java Cryptography. USA: O'Reilly.
Blakeley, Harris, Lewis. 1995. Messaging and Queueing Using the MQI. USA:
McGraw-Hill.
Monson Haefel and Chappel. 2001. Java Message Service. USA: O'Reilly.

Copyright © 2001, DevelopMentor Inc. 743

Vous aimerez peut-être aussi