GJavaDocs

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

Transcript of GJavaDocs

Page 1: GJavaDocs

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

Page 2: GJavaDocs
Page 3: GJavaDocs

Guerrilla Java

Copyright © 2001, DevelopMentor Inc. iii

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

Page 4: GJavaDocs

Guerrilla Java

iv Copyright © 2001, DevelopMentor Inc.

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

Page 5: GJavaDocs

Guerrilla Java

Copyright © 2001, DevelopMentor Inc. v

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

Page 6: GJavaDocs

Guerrilla Java

vi Copyright © 2001, DevelopMentor Inc.

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

Page 7: GJavaDocs

Guerrilla Java

Copyright © 2001, DevelopMentor Inc. vii

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

Page 8: GJavaDocs

Guerrilla Java

viii Copyright © 2001, DevelopMentor Inc.

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

Page 9: GJavaDocs

Guerrilla Java

Copyright © 2001, DevelopMentor Inc. ix

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

Page 10: GJavaDocs

Guerrilla Java

x Copyright © 2001, DevelopMentor Inc.

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

Page 11: GJavaDocs

Guerrilla Java

Copyright © 2001, DevelopMentor Inc. xi

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

Page 12: GJavaDocs

Guerrilla Java

xii Copyright © 2001, DevelopMentor Inc.

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

Page 13: GJavaDocs

Guerrilla Java

Copyright © 2001, DevelopMentor Inc. xiii

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

Page 14: GJavaDocs

Guerrilla Java

xiv Copyright © 2001, DevelopMentor Inc.

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

Page 15: GJavaDocs

Guerrilla Java

Copyright © 2001, DevelopMentor Inc. xv

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

Page 16: GJavaDocs

Guerrilla Java

xvi Copyright © 2001, DevelopMentor Inc.

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

Page 17: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 17

Module 1

HTTP

Page 18: GJavaDocs

18 Copyright © 2001, DevelopMentor Inc.

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

Page 19: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 19

HTTP Basics

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

Page 20: GJavaDocs

Module 1: HTTP

20 Copyright © 2001, DevelopMentor Inc.

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

Page 21: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 21

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.

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

Who?

What?

Input

Output

Figure 1.1: RPC

Page 22: GJavaDocs

Module 1: HTTP

22 Copyright © 2001, DevelopMentor Inc.

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

Page 23: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 23

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.

Page 24: GJavaDocs

Module 1: HTTP

24 Copyright © 2001, DevelopMentor Inc.

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

Page 25: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 25

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.

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

Protocol

Host

Port

Absolute Path

../five/childof5

Relative Path

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.

Page 26: GJavaDocs

Module 1: HTTP

26 Copyright © 2001, DevelopMentor Inc.

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");

Page 27: GJavaDocs
Page 28: GJavaDocs

Module 1: HTTP

28 Copyright © 2001, DevelopMentor Inc.

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

Page 29: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 29

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

BodyHeadersStatus-Line BodyHeadersStatus-Line

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.

<request or status line><other headers>Content-Length: 12Content-Type: text/plain

Hello, World

Format/Lengthof Body

Message Body

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

Page 30: GJavaDocs

Module 1: HTTP

30 Copyright © 2001, DevelopMentor Inc.

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

Page 31: GJavaDocs
Page 32: GJavaDocs

Module 1: HTTP

32 Copyright © 2001, DevelopMentor Inc.

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

Page 33: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 33

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.

GET /object/four HTTP/1.1Headers go here

Request-Line

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.

Page 34: GJavaDocs

Module 1: HTTP

34 Copyright © 2001, DevelopMentor Inc.

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.1Host: betty.develop.com

Figure 1.7: HTTP GET example

POST /object/four HTTP/1.1Host: betty.develop.com:8080Content-Length: 12Content-Type: text/plain

Hello, World

Figure 1.8: HTTP POST example

Page 35: GJavaDocs
Page 36: GJavaDocs

Module 1: HTTP

36 Copyright © 2001, DevelopMentor Inc.

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)

Page 37: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 37

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

OKSee Other

Temp. RedirectBad Request

200303307400401 Unauthorized

SuccessRedirect to different URL (get)

Redirect to different URL (repost)Malformed Request Msg

Access Denied

404 Not Found Unknown resource405 Bad Method HTTP method not supported500 Exec Failure Server-side error501 Not supported Un-recognized HTTP method

DescriptionHTTP InterpretationContinue100 Request Acknowledged

403 Forbidden Illegal operation request

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

Page 38: GJavaDocs

Module 1: HTTP

38 Copyright © 2001, DevelopMentor Inc.

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

Page 39: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 39

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.

HTTP/1.1 303 See OtherLocation: http://helen.com/ep

HTTP/1.1 307 Temporary RedirectLocation: http://helen.com/ep

Client will “GET” this URL

Client will resubmit to this URL

Figure 1.10: 303 and 307 Response Codes

Page 40: GJavaDocs
Page 41: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 41

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.

Page 42: GJavaDocs

Module 1: HTTP

42 Copyright © 2001, DevelopMentor Inc.

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

Page 43: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 43

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

Page 44: GJavaDocs

Module 1: HTTP

44 Copyright © 2001, DevelopMentor Inc.

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

Page 45: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 45

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.

Page 46: GJavaDocs

Module 1: HTTP

46 Copyright © 2001, DevelopMentor Inc.

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)

Page 47: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 47

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.

Page 48: GJavaDocs
Page 49: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 49

Client Code

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

Page 50: GJavaDocs

Module 1: HTTP

50 Copyright © 2001, DevelopMentor Inc.

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

Page 51: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 51

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.

Page 52: GJavaDocs

Module 1: HTTP

52 Copyright © 2001, DevelopMentor Inc.

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

Page 53: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 53

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 = newInputStreamReader(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

Page 54: GJavaDocs

Module 1: HTTP

54 Copyright © 2001, DevelopMentor Inc.

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 = newOutputStreamWriter(con.getOutputStream());writer.write(strOut);writer.flush();

con.connect();

// as doGet to read the data

Figure 1.12: Simple Client POST

Page 55: GJavaDocs

Module 1: HTTP

Copyright © 2001, DevelopMentor Inc. 55

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

Page 56: GJavaDocs
Page 57: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 57

Module 2

Servlets I

Page 58: GJavaDocs

58 Copyright © 2001, DevelopMentor Inc.

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

Page 59: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 59

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.

Page 60: GJavaDocs

Module 2: Servlets i

60 Copyright © 2001, DevelopMentor Inc.

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

Page 61: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 61

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.

Page 62: GJavaDocs

Module 2: Servlets i

62 Copyright © 2001, DevelopMentor Inc.

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

Page 63: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 63

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.

Container

3

4

5

Servletpublic void service{}

HttpServletRequest

HttpServletResponse4

3

5

Client sends an HTTP requestGET /books/bookorder HTTP/1.1

Servlet loaded from file system if necessaryContainer constructs a javax.servlet.http.HttpServletRequest

objectContainer constructs a javax.servlet.http.HttpServletResponse

objectContainer calls servlet's service method

1

2

client

1

2

Figure 2.1: Servlet Loading

Page 64: GJavaDocs

Module 2: Servlets i

64 Copyright © 2001, DevelopMentor Inc.

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.

<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>

GET /books/servlet/Logon HTTP/1.1

GET /books/DoLogon HTTP/1.1

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

GET /books/Alice.lgn HTTP/1.1

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

Page 65: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 65

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

Page 66: GJavaDocs

Module 2: Servlets i

66 Copyright © 2001, DevelopMentor Inc.

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

Page 67: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 67

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.

Page 68: GJavaDocs

Module 2: Servlets i

68 Copyright © 2001, DevelopMentor Inc.

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.

Page 69: GJavaDocs
Page 70: GJavaDocs

Module 2: Servlets i

70 Copyright © 2001, DevelopMentor Inc.

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

Page 71: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 71

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(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…

public void service(ServletRequest req, ServletResponse resp){service ((HttpServletRequest) req, (HttpServletResponse)resp)

}

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!

Page 72: GJavaDocs

Module 2: Servlets i

72 Copyright © 2001, DevelopMentor Inc.

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

Page 73: GJavaDocs
Page 74: GJavaDocs

Module 2: Servlets i

74 Copyright © 2001, DevelopMentor Inc.

HTTP Request Processing

HttpServletRequest provides access to HTTP request

• Headers

• Query string

• Session information

• Etc.

Page 75: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 75

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=barHost: 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()

Page 76: GJavaDocs

Module 2: Servlets i

76 Copyright © 2001, DevelopMentor Inc.

Response Processing

HttpServletResponse

• Provides Access to HTTP Response

• Set the status code

• Set response headers

• Set the response body

Page 77: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 77

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

Page 78: GJavaDocs

Module 2: Servlets i

78 Copyright © 2001, DevelopMentor Inc.

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

Page 79: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 79

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.

<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>

public void init(){// In 'named' servlet onlyString url = getServletConfig().getParameter("url");

}

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.

Page 80: GJavaDocs

Module 2: Servlets i

80 Copyright © 2001, DevelopMentor Inc.

init, destroy, service

Servlet

Gives access to initialisationparams and ServletContext

Abstract class – doesn’t implement service()

Concrete class – service method calls appropriate helper

HttpServlet

GenericServlet

ServletConfig

ServletContextImplementsdoXXX()

MyServlet

Figure 2.10: Bringing it all together

Page 81: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 81

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.

Page 82: GJavaDocs

Module 2: Servlets i

82 Copyright © 2001, DevelopMentor Inc.

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"

Page 83: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 83

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.

Page 84: GJavaDocs

Module 2: Servlets i

84 Copyright © 2001, DevelopMentor Inc.

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 servletRequestDispatcher 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.

Page 85: GJavaDocs
Page 86: GJavaDocs

Module 2: Servlets i

86 Copyright © 2001, DevelopMentor Inc.

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()

Page 87: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 87

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

Page 88: GJavaDocs

Module 2: Servlets i

88 Copyright © 2001, DevelopMentor Inc.

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");

Page 89: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 89

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.

Page 90: GJavaDocs
Page 91: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 91

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.

Page 92: GJavaDocs

Module 2: Servlets i

92 Copyright © 2001, DevelopMentor Inc.

Configuration

We just talked about lots of programming

• Configuration is extremely important

• EJB deployment

• Web deployment

• Already seen servlet configuration

Page 93: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 93

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.

Page 94: GJavaDocs

Module 2: Servlets i

94 Copyright © 2001, DevelopMentor Inc.

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

Page 95: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 95

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

Page 96: GJavaDocs

Module 2: Servlets i

96 Copyright © 2001, DevelopMentor Inc.

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

Page 97: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 97

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

Page 98: GJavaDocs

Module 2: Servlets i

98 Copyright © 2001, DevelopMentor Inc.

<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.

Page 99: GJavaDocs

Module 2: Servlets i

Copyright © 2001, DevelopMentor Inc. 99

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

Page 100: GJavaDocs
Page 101: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 101

Module 3

JSP

Page 102: GJavaDocs

102 Copyright © 2001, DevelopMentor Inc.

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

Page 103: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 103

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.

Page 104: GJavaDocs

Module 3: JSP

104 Copyright © 2001, DevelopMentor Inc.

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

Page 105: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 105

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()

4: Delegate()

5: Dispatch()

Bean

6: RetrieveContent()

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

3: execute()

Figure 3.1: Interaction Between a Servlet and a JSP

Page 106: GJavaDocs

Module 3: JSP

106 Copyright © 2001, DevelopMentor Inc.

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

Page 107: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 107

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.

<% response.setContentType("text/xml"); %><response><name>Password</name><value><% out.write("Fred"); %></value></response>

MyJSP.jsp

<%@ page contentType="text/xml" %><response><name>Password</name><value><% out.write("Fred"); %></value></response>

MyJSP.jsp

<response><name>Password</name><value>Fred</value></response>

Client sees this

<response><name>Password</name><value>Fred</value></response>

Client sees this

public void service(…){

JspWriter out = pageContext.getInitialOut();

response.setContentType("text/xml");

out.write("<response><name>Password</name>");

out.write("<value>");out.write("Fred");out.write"</value></response>");

}

produces this

public void service(…){

JspWriter out = pageContext.getInitialOut();

response.setContentType("text/xml");

out.write("<response><name>Password</name>");

out.write("<value>");out.write("Fred");out.write"</value></response>");

}

produces this

Figure 3.2: Translation and output of a simple JSP

Page 108: GJavaDocs

Module 3: JSP

108 Copyright © 2001, DevelopMentor Inc.

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

Page 109: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 109

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.

Page 110: GJavaDocs

Module 3: JSP

110 Copyright © 2001, DevelopMentor Inc.

Producing Output

JSPs produce textual output

• <book name="JSP" />

• <% out.write("Homer Rules"); %>

• <value>value is <%= b.getValue() %></value>

Page 111: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 111

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

Page 112: GJavaDocs

Module 3: JSP

112 Copyright © 2001, DevelopMentor Inc.

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

Page 113: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 113

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.

Page 114: GJavaDocs

Module 3: JSP

114 Copyright © 2001, DevelopMentor Inc.

<%! int j; %>

public class SomeJSP extends HttpServlet,implements HttpJspPage {

...int j = 0;void _jspService(...) {

...}

}

Figure 3.7: Use of Declarations in JSP

Page 115: GJavaDocs
Page 116: GJavaDocs

Module 3: JSP

116 Copyright © 2001, DevelopMentor Inc.

Directives

Used to control various aspects of the generated code

• Page

• Include

• Taglib

• Of form <%@ directive attr_list %>

Page 117: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 117

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.

Page 118: GJavaDocs

Module 3: JSP

118 Copyright © 2001, DevelopMentor Inc.

Attributes What does it do Default

extends class that the servlet extends none

import classes imported into servlet noneisThreadSafe if false implements SingleThreadModel true

buffer JSPWriter buffer size 8kb

autoFlush should JSPWriter flush if full truesession automatic session true

errorPage what is the error page associated with this page? none

isErrorPage is this page an error page? falselanguage what is the scripting language Java

info getServletInfo none

contentType content type of the generated page text/htmlpageEncoding character encoding of the generated page ISO-8859-1

Figure 3.10: JSP Page Directive Usage

Page 119: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 119

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.

Page 120: GJavaDocs

Module 3: JSP

120 Copyright © 2001, DevelopMentor Inc.

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

Page 121: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 121

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 implementsjava.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

Page 122: GJavaDocs

Module 3: JSP

122 Copyright © 2001, DevelopMentor Inc.

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 = newjava.util.Date(); %>

Figure 3.12: Initializing a bean using an action, with the generated code.

Page 123: GJavaDocs
Page 124: GJavaDocs

Module 3: JSP

124 Copyright © 2001, DevelopMentor Inc.

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'

Page 125: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 125

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.

Page 126: GJavaDocs

Module 3: JSP

126 Copyright © 2001, DevelopMentor Inc.

'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.

Page 127: GJavaDocs
Page 128: GJavaDocs

Module 3: JSP

128 Copyright © 2001, DevelopMentor Inc.

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

Page 129: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 129

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.

Page 130: GJavaDocs

Module 3: JSP

130 Copyright © 2001, DevelopMentor Inc.

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).

Page 131: GJavaDocs

Module 3: JSP

Copyright © 2001, DevelopMentor Inc. 131

<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

Page 132: GJavaDocs

Module 3: JSP

132 Copyright © 2001, DevelopMentor Inc.

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

Page 133: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 133

Module 4

EJB Introduction

Page 134: GJavaDocs

134 Copyright © 2001, DevelopMentor Inc.

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

Page 135: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 135

Introduction to the EJB model

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

Page 136: GJavaDocs

Module 4: EJB Introduction

136 Copyright © 2001, DevelopMentor Inc.

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

Page 137: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 137

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

Page 138: GJavaDocs

Module 4: EJB Introduction

138 Copyright © 2001, DevelopMentor Inc.

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.

Page 139: GJavaDocs
Page 140: GJavaDocs

Module 4: EJB Introduction

140 Copyright © 2001, DevelopMentor Inc.

Remote Procedure Call

RMI is Java's version of RPC

• Java syntax

• Request / response semantics

• Latency

• Communications failures

• Parameter serialization

Page 141: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 141

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.

Page 142: GJavaDocs

Module 4: EJB Introduction

142 Copyright © 2001, DevelopMentor Inc.

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

Page 143: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 143

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

Page 144: GJavaDocs

Module 4: EJB Introduction

144 Copyright © 2001, DevelopMentor Inc.

Java Remote Method Protocol (JRMP)

JRMP is the original RMI protocol

• Object serialization

• Distributed GC

• Preferred by the JINI crowd

Page 145: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 145

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.

Page 146: GJavaDocs

Module 4: EJB Introduction

146 Copyright © 2001, DevelopMentor Inc.

Internet Inter-Orb Protocol (IIOP)

IIOP supported by the CORBA crowd

• Objects by value

• No GC

• Split identities

• Preferred by the EJB crowd

Page 147: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 147

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 IIOPTestRMIItf itf = (TestRMIItf) PortableRemoteObject.narrow(

Naming.lookup("TestRMIServer"),TestRMIItf.class);

Figure 4.1: Always use PortableRemoteObject.narrow for RMI casts

Page 148: GJavaDocs
Page 149: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 149

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.

Page 150: GJavaDocs

Module 4: EJB Introduction

150 Copyright © 2001, DevelopMentor Inc.

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

Page 151: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 151

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

EJB object bean

context(run-time environment)

RMIskeleton

RMIstub

systemservices

deploymentdescriptor

defines services to construct interposer

calls platform code

EJB home

RMIskeleton

RMIstub

homeinterface

remoteinterface

developer defined

container generated

creates, finds, deletes

Figure 4.2: EJB interposition model

Page 152: GJavaDocs

Module 4: EJB Introduction

152 Copyright © 2001, DevelopMentor Inc.

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

Page 153: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 153

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

Page 154: GJavaDocs

Module 4: EJB Introduction

154 Copyright © 2001, DevelopMentor Inc.

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.

Page 155: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 155

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

Page 156: GJavaDocs

Module 4: EJB Introduction

156 Copyright © 2001, DevelopMentor Inc.

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 createmethodpublic 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.

Page 157: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 157

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

interfacepublic void ejbCreate() {...}// Method signatures mandated by SessionBean interfacepublic void ejbRemove() {...}public void ejbActivate() {...}public void ejbPassivate() {...}public void setSessionContext(SessionContext ctx) {...}

// Method signatures must "match" those in remoteinterfacepublic 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...

Page 158: GJavaDocs

Module 4: EJB Introduction

158 Copyright © 2001, DevelopMentor Inc.

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

Page 159: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 159

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

Page 160: GJavaDocs

Module 4: EJB Introduction

160 Copyright © 2001, DevelopMentor Inc.

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 interfacepublic void ejbCreate() {...}

// Method signatures mandated by SessionBean interfacepublic void ejbRemove() {...}public void ejbActivate() {...}public void ejbPassivate() {...}public void setSessionContext(SessionContext ctx) {...}

// Methods in local TellerMethods interfacepublic boolean deposit(Money m,Account a){}...

}

Figure 4.8: Revised bean class (for a stateless session)

Page 161: GJavaDocs
Page 162: GJavaDocs

Module 4: EJB Introduction

162 Copyright © 2001, DevelopMentor Inc.

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

Page 163: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 163

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

}

Page 164: GJavaDocs

Module 4: EJB Introduction

164 Copyright © 2001, DevelopMentor Inc.

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

Page 165: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 165

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)

Page 166: GJavaDocs

Module 4: EJB Introduction

166 Copyright © 2001, DevelopMentor Inc.

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.

Page 167: GJavaDocs
Page 168: GJavaDocs

Module 4: EJB Introduction

168 Copyright © 2001, DevelopMentor Inc.

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

Page 169: GJavaDocs

Module 4: EJB Introduction

Copyright © 2001, DevelopMentor Inc. 169

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)

Page 170: GJavaDocs

Module 4: EJB Introduction

170 Copyright © 2001, DevelopMentor Inc.

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

Page 171: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 171

Module 5

XML

Page 172: GJavaDocs

172 Copyright © 2001, DevelopMentor Inc.

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

Page 173: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 173

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.

Page 174: GJavaDocs

Module 5: XML

174 Copyright © 2001, DevelopMentor Inc.

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

Page 175: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 175

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.

XML Type System Internal Type System

Lib1 Lib2 Lib3

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.

Page 176: GJavaDocs

Module 5: XML

176 Copyright © 2001, DevelopMentor Inc.

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 }

Element: { null, age }

Characters: David Smith

Characters: 38

<?xml version="1.0" encoding="UTF-16" ?><ns:student xmlns:ns="xyzzy:abc"><name>David &#83;mith</name><age>38</age>

</ns:student>

XML Infoset(Abstract Model)

XML 1.0 + NS(Concrete Syntax)

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

Page 177: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 177

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 IIS

XML

Pars

er

XML-basedProcessingSoftware

Figure 5.3: Traditional DBMS/XML solution

TDS (or equivalent)

JDBC

Web

Row

set (

or E

quiv

alen

t)

XML-basedProcessingSoftware

Figure 5.4: Just-in-time XML

Page 178: GJavaDocs

Module 5: XML

178 Copyright © 2001, DevelopMentor Inc.

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!

Page 179: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 179

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.

Page 180: GJavaDocs

Module 5: XML

180 Copyright © 2001, DevelopMentor Inc.

Document: http://www.develop.com/roster.xml

{ xyzzy:abc, person } : { xyzzy:abc, student }

{ schema-ns, string } : { null, name }

{ schema-ns, double } : { null, age }

string: David Smith

double: 38.0

Post-SchemaXML Infoset

(Abstract Model)

<xsd:schemaxmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:tns="xyzzy:abc"targetNamespace="xyzzy:abc"

><xsd:complexType name="person" >

<xsd:sequence><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>

XML 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.

Page 181: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 181

.NET TypeInformation

COM TypeInformation

DBMS TypeInformation

DirectoryType

Information

JVM TypeInformation

AutomaticSerialization

RemoteMethod

Invocation

SmartEditors

CodeGeneration

GeneralPurpose

Validators

XML Schema

Figure 5.6: The role of XML Schemas

XML Schema Type Programmatic Type

XML InstanceDocuments Objects and Values

Figure 5.7: Bridging the XML type system

Page 182: GJavaDocs

Module 5: XML

182 Copyright © 2001, DevelopMentor Inc.

'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

Page 183: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 183

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.

Page 184: GJavaDocs
Page 185: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 185

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.

Page 186: GJavaDocs

Module 5: XML

186 Copyright © 2001, DevelopMentor Inc.

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

Page 187: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 187

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.

Page 188: GJavaDocs

Module 5: XML

188 Copyright © 2001, DevelopMentor Inc.

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)

Page 189: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 189

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 implementsContentHandler,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).

Page 190: GJavaDocs

Module 5: XML

190 Copyright © 2001, DevelopMentor Inc.

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

Page 191: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 191

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

Page 192: GJavaDocs

Module 5: XML

192 Copyright © 2001, DevelopMentor Inc.

InputSource

Abstracts away location of input XML

• Defined in SAX Packages

• Also used by DOM parsers

• Build InputSource on a stream or SystemId

Page 193: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 193

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.

Page 194: GJavaDocs
Page 195: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 195

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

Page 196: GJavaDocs

Module 5: XML

196 Copyright © 2001, DevelopMentor Inc.

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

Page 197: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 197

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.

Page 198: GJavaDocs

Module 5: XML

198 Copyright © 2001, DevelopMentor Inc.

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

Page 199: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 199

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.

<?xml version="1.0"?>

<?order alpha ascending?>

<!-- renaissance art period -->

<period name="Renaissance">

<artist>Leonardo da Vinci</artist>

<artist>Michelangelo</artist>

<artist>Donatello</artist>

</period>

Document

P. Instruction Comment Element

Element Element Element

Text Text Text

Text

AttrDocument

P. Instruction Comment Element

Element Element Element

Text Text Text

Text

Attr

Figure 5.12: DOM logical structure example

Page 200: GJavaDocs

Module 5: XML

200 Copyright © 2001, DevelopMentor Inc.

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)

Page 201: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 201

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"

Node

Attr

CharacterData

DocumentType

DocumentFragment

Document

Element

Entity

EntityReference

Notation

ProcessingInstruction

Attr

CharacterData

DocumentType

DocumentFragment

Document

Element

Entity

EntityReference

Notation

ProcessingInstruction

Comment

Text

Comment

Text

CDATASectionCDATASection

DOMImplementation

NamedNodeMap

NodeList

DOMException

Figure 5.13: DOM Interface Hierarchy

Page 202: GJavaDocs

Module 5: XML

202 Copyright © 2001, DevelopMentor Inc.

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

Page 203: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 203

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.

Page 204: GJavaDocs

Module 5: XML

204 Copyright © 2001, DevelopMentor Inc.

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)

Page 205: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 205

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.Stringname)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.

Page 206: GJavaDocs

Module 5: XML

206 Copyright © 2001, DevelopMentor Inc.

<?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

Page 207: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 207

Using XPath

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

Page 208: GJavaDocs

Module 5: XML

208 Copyright © 2001, DevelopMentor Inc.

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

Page 209: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 209

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.

Page 210: GJavaDocs

Module 5: XML

210 Copyright © 2001, DevelopMentor Inc.

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

Page 211: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 211

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 "/".

Page 212: GJavaDocs

Module 5: XML

212 Copyright © 2001, DevelopMentor Inc.

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

Page 213: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 213

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.

root

guitar

model model model

texttexttext

Les Paul Tele Strat

guitars

guitar

text

Les Paul

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

model

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

Page 214: GJavaDocs

Module 5: XML

214 Copyright © 2001, DevelopMentor Inc.

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

initial location step location step location step

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

axis node test predicate

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><guitartype='Electric'>Stratocastor</guitar></guitars> would remain in the node set but <guitars><guitartype='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"

Page 215: GJavaDocs

Module 5: XML

Copyright © 2001, DevelopMentor Inc. 215

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

Page 216: GJavaDocs
Page 217: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 217

Module 6

JDBC

Page 218: GJavaDocs

218 Copyright © 2001, DevelopMentor Inc.

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

Page 219: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 219

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.

Page 220: GJavaDocs

Module 6: JDBC

220 Copyright © 2001, DevelopMentor Inc.

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

Page 221: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 221

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.

“ThePrinter” <reference>

“FileServer”

“Raoul”

“Sanjay”

“Root” context

<reference>

<reference>

<reference>

“Printers” <reference>

“Employees” <reference> “Laser1” <reference>

“Color1”

“Printers” context

<reference>

“Homer”

“192.168.0.1”

<reference>

<reference>

“Computers” contextbinding

“ThePrinter” <reference>

“FileServer”

“Raoul”

“Sanjay”

“Root” context

<reference>

<reference>

<reference>

“Printers” <reference>

“Employees” <reference> “Laser1” <reference>

“Color1”

“Printers” context

<reference>

“Homer”

“192.168.0.1”

<reference>

<reference>

“Computers” contextbinding

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.

Page 222: GJavaDocs

Module 6: JDBC

222 Copyright © 2001, DevelopMentor Inc.

“Employee” directory context

Name Raoul

Badge No. 137497

Job Title Hosist

E-mail raoul@ourmail

Name Raoul

Badge No. 137497

Job Title Hosist

E-mail raoul@ourmail

Name Sanjay

Badge No. 009126

Job Title Middle Manager

E-mail sanjay@ourmail

Name Sanjay

Badge No. 009126

Job Title Middle Manager

E-mail sanjay@ourmail

Figure 6.2: A directory

Page 223: GJavaDocs
Page 224: GJavaDocs

Module 6: JDBC

224 Copyright © 2001, DevelopMentor Inc.

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

Page 225: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 225

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.

JNDI API

Client of JNDI APIClient of JNDI API

Naming Manager

SPI Implementation

Service Provider Interface

javax.naming.*javax.naming.directory.*javax.naming.spi.*…

Figure 6.3: JNDI architecture

Page 226: GJavaDocs

Module 6: JDBC

226 Copyright © 2001, DevelopMentor Inc.

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

Page 227: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 227

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.Contextjavax.naming.Context

javax.naming.directory.DirContextjavax.naming.directory.DirContextjavax.naming.InitialContext

javax.naming.directory.InitialDirContext

extends

extendsimplements

implements

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

Page 228: GJavaDocs

Module 6: JDBC

228 Copyright © 2001, DevelopMentor Inc.

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.RefFSContextFactoryjava.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

Page 229: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 229

Data access with JDBC

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

Page 230: GJavaDocs

Module 6: JDBC

230 Copyright © 2001, DevelopMentor Inc.

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

Page 231: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 231

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

MSSQL Driver

JNDI

Oracle Driver

JDBC DriverManager

Sybase 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.

Page 232: GJavaDocs

Module 6: JDBC

232 Copyright © 2001, DevelopMentor Inc.

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.

Type Client Native Code?

Server Native Code?

1 yes no

2 yes maybe

3 no maybe

4 no no

Meaning

ODBC bridge driver

Mix ‘n’ match

Net driver

Pure Java driver

Figure 6.8: JDBC driver types

Page 233: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 233

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.

Page 234: GJavaDocs

Module 6: JDBC

234 Copyright © 2001, DevelopMentor Inc.

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

Page 235: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 235

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.

DataSource (JDBC 2)

Statement

createStatement()

PreparedStatement

prepareStatement()

ResultSet

executeQuery()

getXXX()

executeQuery()

setXXX()

DataTypes,string int etc

prepareCall()

DriverManager (JDBC 1)

getConnection()

classinterface

Connection

CallableStatementDatabaseMetaData

getMetaData()

ResultSetMetaData

getMetaData()

getXXX()

Figure 6.9: JDBC programming model

Page 236: GJavaDocs

Module 6: JDBC

236 Copyright © 2001, DevelopMentor Inc.

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

Page 237: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 237

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

MSSQL Driver

JNDI

Oracle Driver

JDBC DriverManager

Sybase 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=.

Page 238: GJavaDocs

Module 6: JDBC

238 Copyright © 2001, DevelopMentor Inc.

jdbc:<subprotocol>:<subname>

Always jdbc Driver name ordriver

connectivitymechanism

Driver-specificsyntax to

identify source

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=sa&pwd=";// ... and makes the connectionreturn 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

Page 239: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 239

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 filejdbcXADataSource.1.name=jdbc/MyDSjdbcXADataSource.1.classname=com.jnetdirect.jsql.JSQLXADataSourcejdbcXADataSource.1.dbuser=sajdbcXADataSource.1.dbpassword=jdbcXADataSource.1.prop.serverName=localhostjdbcXADataSource.1.prop.portNumber=1433jdbcXADataSource.1.prop.databaseName=mydb

Figure 6.13: Example server DataSource configuration

// This is what the J2EE server doespublic 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.

Page 240: GJavaDocs

Module 6: JDBC

240 Copyright © 2001, DevelopMentor Inc.

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 connectionreturn 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().

Page 241: GJavaDocs
Page 242: GJavaDocs

Module 6: JDBC

242 Copyright © 2001, DevelopMentor Inc.

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

Page 243: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 243

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

Page 244: GJavaDocs

Module 6: JDBC

244 Copyright © 2001, DevelopMentor Inc.

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

Page 245: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 245

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(intcolIndex) 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.

Page 246: GJavaDocs

Module 6: JDBC

246 Copyright © 2001, DevelopMentor Inc.

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 ( "FirstName:"+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().

Page 247: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 247

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.

Page 248: GJavaDocs

Module 6: JDBC

248 Copyright © 2001, DevelopMentor Inc.

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

Page 249: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 249

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)

ASUPDATE 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 ({? = callprocedure_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().

Page 250: GJavaDocs

Module 6: JDBC

250 Copyright © 2001, DevelopMentor Inc.

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 countstmt.getMoreResults();continue;

}if((rs = stmt.getResultSet()) != null) { // a result set

stmt.getMoreResults();continue;

}break;

}

Figure 6.21: Handling multiple results

Page 251: GJavaDocs
Page 252: GJavaDocs

Module 6: JDBC

252 Copyright © 2001, DevelopMentor Inc.

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

Page 253: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 253

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.

Page 254: GJavaDocs

Module 6: JDBC

254 Copyright © 2001, DevelopMentor Inc.

ResultSet rs = stmt.excuteQuery();CachedRowSet crs = new CachedRowSet();crs.populate(rs);smt.close();con.close(); // now we are disconnectedObjectOutputStream 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 ( "FirstName:"+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 = newjava.io.FileWriter("file.xml");

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

Figure 6.23: Using a WebRowset

Page 255: GJavaDocs
Page 256: GJavaDocs

Module 6: JDBC

256 Copyright © 2001, DevelopMentor Inc.

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

Page 257: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 257

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.

Page 258: GJavaDocs

Module 6: JDBC

258 Copyright © 2001, DevelopMentor Inc.

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

// Batching any SQLString 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

Page 259: GJavaDocs

Module 6: JDBC

Copyright © 2001, DevelopMentor Inc. 259

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

Page 260: GJavaDocs
Page 261: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 261

Module 7

Transactions

Page 262: GJavaDocs

262 Copyright © 2001, DevelopMentor Inc.

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

Page 263: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 263

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.

Page 264: GJavaDocs

Module 7: Transactions

264 Copyright © 2001, DevelopMentor Inc.

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

Page 265: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 265

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.

Page 266: GJavaDocs

Module 7: Transactions

266 Copyright © 2001, DevelopMentor Inc.

Transaction basics

ACID properties guaranteed

• Simple agent API: commit or abort

• Resource Managers (RMs) manage data

• Transaction Managers (TMs) coordinate parties

Page 267: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 267

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

Page 268: GJavaDocs

Module 7: Transactions

268 Copyright © 2001, DevelopMentor Inc.

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

Page 269: GJavaDocs
Page 270: GJavaDocs

Module 7: Transactions

270 Copyright © 2001, DevelopMentor Inc.

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()

Page 271: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 271

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.

Agent

ResourceManager

(with own internal

TransactionManager)

1. Acquire transacted resource

2. Use transacted resource

3. Commit (or abort) transacted resource

4. OK (or not)

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 BEGINTRANSACTION and ended with COMMIT or ROLLBACK. The stored procedure in figure 7.2 shows how.

CREATE PROCEDURE transfer@id integer,@amount integer

ASBEGIN TRANSACTIONupdate savings set amount = amount+@amount where id=@idupdate checking set amount = amount-@amount where id=@idCOMMIT

}

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 BEGINTRANSACTION 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.

Page 272: GJavaDocs

Module 7: Transactions

272 Copyright © 2001, DevelopMentor Inc.

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.

Page 273: GJavaDocs
Page 274: GJavaDocs

Module 7: Transactions

274 Copyright © 2001, DevelopMentor Inc.

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

Page 275: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 275

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.

Page 276: GJavaDocs

Module 7: Transactions

276 Copyright © 2001, DevelopMentor Inc.

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

Page 277: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 277

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.

No

Chaos ReadUncommitted

ReadCommitted

RepeatableRead Serializable

Yes

Yes

Yes

Yes

Yes

Yes Yes

YesYes Yes

No No No No

No No

No

No

No

Common Name

Lost Updates?

Dirty Reads?

UnrepeatableReads?

Phantoms?

Degree 0 1 2 2.999... 3

Figure 7.4: Transaction isolation levels

Page 278: GJavaDocs

Module 7: Transactions

278 Copyright © 2001, DevelopMentor Inc.

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

Page 279: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 279

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 ... FORUPDATE 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 levelrepeatable 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.

Page 280: GJavaDocs

Module 7: Transactions

280 Copyright © 2001, DevelopMentor Inc.

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

Page 281: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 281

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

Page 282: GJavaDocs

Module 7: Transactions

282 Copyright © 2001, DevelopMentor Inc.

is sometimes called "optimistic locking" as the implementation is fairly optimistic that in most cases the data will not have changed.

Middle-tier

databaseTx1: SELECT WHERE …

Tx2: IF … UPDATE …

Client

Timestamp+ data

Timestamp+ data

Timestamp+ updated data

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.

Page 283: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 283

check securityvalidate args

work with cacheacquire resources

start txone call to RM

end tx

release resources perform async processing

format output

Figure 7.7: Shorten code path inside transaction

Page 284: GJavaDocs
Page 285: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 285

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.

Page 286: GJavaDocs

Module 7: Transactions

286 Copyright © 2001, DevelopMentor Inc.

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

Page 287: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 287

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.

Machine C

Machine A

Machine B

agent (root)

TM1RM1 RM2

RM3 RM4TM2 TM3

agent

Distributed transaction

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.

Page 288: GJavaDocs

Module 7: Transactions

288 Copyright © 2001, DevelopMentor Inc.

agent

acquire tx1. Acquire resources2. Acquire transaction3. Enlist resources on

transaction4. Use resources5. Commit/abort

transaction

TM

RM

RM

enlist

enlist

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

Page 289: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 289

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

Page 290: GJavaDocs

Module 7: Transactions

290 Copyright © 2001, DevelopMentor Inc.

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.

TM

RM 2RM 3

RM 4 RM 1No!

OK OK

OK

Figure 7.12: The problem of coordinating multi-party commit

agentCommit

TM RM

RM

Phase 1: votePhase 2: notifyPhase 1: votePhase 2: notify

Result

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.

Page 291: GJavaDocs

Module 7: Transactions

Copyright © 2001, DevelopMentor Inc. 291

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

Page 292: GJavaDocs
Page 293: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 293

Module 8

EJB Declarative Transactions

Page 294: GJavaDocs

294 Copyright © 2001, DevelopMentor Inc.

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

Page 295: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 295

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.

Page 296: GJavaDocs

Module 8: EJB Declarative Transactions

296 Copyright © 2001, DevelopMentor Inc.

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

Page 297: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 297

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

Container code

Bean Aremoteinterface

Containercode

JDBC Driver

Enlist ontransaction

Commit/aborttransaction

Starttransaction

Bean Bremote

interfacePropagate

transaction

Container code

Container code

Bean Aremoteinterface

Containercode

JDBC Driver

Enlist ontransaction

Commit/aborttransaction

Starttransaction

Bean Bremote

interfacePropagate

transaction

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.

Page 298: GJavaDocs

Module 8: EJB Declarative Transactions

298 Copyright © 2001, DevelopMentor Inc.

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.

Page 299: GJavaDocs
Page 300: GJavaDocs

Module 8: EJB Declarative Transactions

300 Copyright © 2001, DevelopMentor Inc.

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

Page 301: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 301

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.

Page 302: GJavaDocs

Module 8: EJB Declarative Transactions

302 Copyright © 2001, DevelopMentor Inc.

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

Page 303: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 303

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

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

Never As NotSupported but fails if caller in tx

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.

Page 304: GJavaDocs

Module 8: EJB Declarative Transactions

304 Copyright © 2001, DevelopMentor Inc.

<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

Page 305: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 305

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.

Required CMT bean

RequiresNew CMT bean

Mandatory CMT bean

tx scope 2calls NotSupported CMT bean

bean inmanaged tx

tx scope 1

Supports CMT bean

Never CMT bean

error!

Figure 8.4: Effect of CMT bean declarative attributes on transaction

bracketing/scope (1)

Required CMT bean

RequiresNew CMT bean

Mandatory CMT bean

tx scope 2

NotSupported CMT bean

bean outsideof managed

txtx scope 1

Supports CMT bean

error!

Never CMT bean

calls

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.

Page 306: GJavaDocs

Module 8: EJB Declarative Transactions

306 Copyright © 2001, DevelopMentor Inc.

C (Supported)

D (Mandatory)

B (Required)A (Required orRequires New)

tx root

Starts tx on way in Stops tx on way out

tx scope

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 scope?

shares callers tx scope?

root of tx scope?

Never Never Never

if caller is if caller has one Never

Always if caller has one if caller doesn’thave one

Always Never Always

Always Always Never

<transaction-attribute>

NotSupported

Supports

Required

RequiresNew

Mandatory

Never Never NeverNever

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.

Page 307: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 307

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 txStatement 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 earlierlogBean.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

Page 308: GJavaDocs

Module 8: EJB Declarative Transactions

308 Copyright © 2001, DevelopMentor Inc.

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

Page 309: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 309

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.

Page 310: GJavaDocs

Module 8: EJB Declarative Transactions

310 Copyright © 2001, DevelopMentor Inc.

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 doomedthrow 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 backto 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

Page 311: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 311

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.

Bean throws… Interposer catches and takes following action…

No exceptionNo exception to catch, no exception thrown to caller

Bean tx marked for rollback if EJBContext.setRollbackOnly calledBean not discarded

System exceptionjavax.transaction.TransactionRolledbackException thrown to caller

Bean tx marked for rollbackBean discarded

Application exceptionException re-thrown to caller

Bean tx marked for rollback if EJBContext.setRollbackOnly calledBean not discarded

CMT bean (ta=Required, Supports or Mandatory)

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

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

Page 312: GJavaDocs

Module 8: EJB Declarative Transactions

312 Copyright © 2001, DevelopMentor Inc.

Bean throws… Interposer catches and takes following action…

No exceptionNo exception to catch, no exception thrown to caller

Callers tx (if any) unaffected *Bean not discarded

System exceptionjavax.rmi.RemoteException thrown to caller

Callers tx (if any) unaffected *Bean discarded

Application exceptionException re-thrown to callerCallers tx (if any) unaffected *

Bean not discarded

CMT bean (ta=Never, NotSupported or Supports)

* 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

Exception re-thrown to callerAbort bean tx if marked for rollback, attempt commit otherwise

Bean not discardedCallers tx (if any) unaffected *

java.rmi. RemoteException thrown to caller **Bean tx abortedBean discarded

Callers tx (if any) unaffected *

No exception to catch, no exception thrown to callerAbort bean tx if marked for rollback, attempt commit otherwise

Bean not discardedCallers tx (if any) unaffected *

Bean throws… Interposer catches and takes following action…

No exception

System exception

Application exception

CMT bean (ta=RequiresNew or Required)

** 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.

Page 313: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 313

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).

Page 314: GJavaDocs

Module 8: EJB Declarative Transactions

314 Copyright © 2001, DevelopMentor Inc.

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

Page 315: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 315

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.

Page 316: GJavaDocs

Module 8: EJB Declarative Transactions

316 Copyright © 2001, DevelopMentor Inc.

public void transfer(){UserTransaction ut = null;try {

ut = ctx.getUserTransaction();ut.begin();<-- 1. Container starts tx with beans helput.setTransactionTimeout(5);DataSource ds=jndictx.lookup("jdbc/MyDB");Connection con=null;con=ds.getConnection();<-- 2. Container enlists

connection in txStatement 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 earlierlogBean.logtransfer();<-- 3. Container propagates tx

to CMT beanut.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

Page 317: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 317

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.

C (Supported)

D (Mandatory)

B (Required)

tx rootA (Bean-managed)

UserTransaction.begin();…UserTransaction.commit();

tx scope

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.

Never

in tx scope? shares callers tx scope? root of tx scope?

Meaning<transaction-type>Like RequiresNew if bean starts txLike NotSupported if bean doesn’t start tx

Bean

Yes if bean starts txNo if bean doesn’t start tx

Yes if bean starts txNo 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.

Page 318: GJavaDocs

Module 8: EJB Declarative Transactions

318 Copyright © 2001, DevelopMentor Inc.

BMT bean that starts a tx

bean outsideof managed

tx

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

bean inmanaged tx

tx scope 1

BMT bean that starts a tx

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

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

Page 319: GJavaDocs
Page 320: GJavaDocs

Module 8: EJB Declarative Transactions

320 Copyright © 2001, DevelopMentor Inc.

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

Page 321: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 321

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.

Application exception

UT.commit() attempts to commit bean tx if not marked for rollbackUT.rollback() aborts bean tx ***Callers tx (if any) unaffected *

No exceptionUT.commit() attempts to commit bean tx if not marked for rollback

UT.rollback() aborts bean tx ***Callers tx (if any) unaffected *

Bean throwsinside of tx… Bean catches and ends tx with UserTransaction.commit()/rollback()…

BMT bean (no transaction attributes)

System exception

UT.commit() aborts bean txUT.rollback() aborts bean tx ***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 asfor 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

Page 322: GJavaDocs

Module 8: EJB Declarative Transactions

322 Copyright © 2001, DevelopMentor Inc.

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.

No exceptionNo exception to catch, no exception thrown to caller

Bean tx keeps running ****Bean not discarded

Callers tx (if any) unaffected *

Bean throwsinside of tx…

Interposer catches without bean calling UserTransaction.commit()/rollback()…

BMTstateful session bean (no transaction attributes)

No exceptionApplication exception re-thrown to caller

Bean tx keeps running ****Bean not discarded

Callers tx (if any) unaffected *java.rmi. RemoteException thrown to caller **

Bean tx abortedBean discarded

Callers tx (if any) unaffected *

System exception

**** 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().

Page 323: GJavaDocs
Page 324: GJavaDocs

Module 8: EJB Declarative Transactions

324 Copyright © 2001, DevelopMentor Inc.

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

Page 325: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 325

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 txpublic 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 outcomepublic 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.

Page 326: GJavaDocs

Module 8: EJB Declarative Transactions

326 Copyright © 2001, DevelopMentor Inc.

does not exist ready

client calls create(…) on home:Class.newInstance()setSessionContext()ejbCreate(…)

client executesnon-tx method

non-tx methodexecution ends

executing

client calls remove():ejbRemove()

passive

container passivates:ejbPassivate()

client calls method and container activates:ejbActivate()

ready in tx

clientexecutesfirst methodin tx:afterBegin()

bean executestx method

tx methodexecution ends

tx ends:afterCompletion(false)

orbeforeCompletion()afterCompletion(true/false)

executingin tx

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

Page 327: GJavaDocs

Module 8: EJB Declarative Transactions

Copyright © 2001, DevelopMentor Inc. 327

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

Page 328: GJavaDocs
Page 329: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 329

Module 9

State Management

Page 330: GJavaDocs

330 Copyright © 2001, DevelopMentor Inc.

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

Page 331: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 331

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.

Page 332: GJavaDocs

Module 9: State Management

332 Copyright © 2001, DevelopMentor Inc.

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

Page 333: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 333

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.

Page 334: GJavaDocs

Module 9: State Management

334 Copyright © 2001, DevelopMentor Inc.

client web server1. Initial client HTTP GET request1. Initial client HTTP GET request

3. Server sends session-id3. Server sends session-id

5. User browses to item ‘A’ page5. User browses to item ‘A’ page

6. User purchases item ‘A’6. User purchases item ‘A’

7. User browses to item ‘B’ page7. User browses to item ‘B’ page

8. User purchases item ‘B’8. User purchases item ‘B’

2. Session and session-id created2. Session and session-id created

9. User goes to checkout9. User goes to checkout

4. Client keeps session-id and its association with the server

This will be sent back and forth in subsequent messages

Book ABook B

Figure 9.1: Using cookies to manage state

Page 335: GJavaDocs
Page 336: GJavaDocs

Module 9: State Management

336 Copyright © 2001, DevelopMentor Inc.

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"/>

Page 337: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 337

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.

Page 338: GJavaDocs

Module 9: State Management

338 Copyright © 2001, DevelopMentor Inc.

public void doGet(...){// true creates a session if none existsHttpSession session = req.getSession(true);Email email = null;if(session.isNew()) {

email = new Email(...);// add values to the sessionsession.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.

Page 339: GJavaDocs
Page 340: GJavaDocs

Module 9: State Management

340 Copyright © 2001, DevelopMentor Inc.

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

Page 341: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 341

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

Page 342: GJavaDocs

Module 9: State Management

342 Copyright © 2001, DevelopMentor Inc.

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

Page 343: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 343

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

Page 344: GJavaDocs

Module 9: State Management

344 Copyright © 2001, DevelopMentor Inc.

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

Page 345: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 345

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.

Page 346: GJavaDocs

Module 9: State Management

346 Copyright © 2001, DevelopMentor Inc.

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

Page 347: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 347

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.

Page 348: GJavaDocs

Module 9: State Management

348 Copyright © 2001, DevelopMentor Inc.

clientclient

web server 2web server 2

web server 1

sessionstate

11

22

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.

Page 349: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 349

client

web server 2

web server 1

11 other server

sessionstate

33

22

44

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.

Page 350: GJavaDocs

Module 9: State Management

350 Copyright © 2001, DevelopMentor Inc.

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

Page 351: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 351

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

Page 352: GJavaDocs

Module 9: State Management

352 Copyright © 2001, DevelopMentor Inc.

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 daysres.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

Page 353: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 353

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.

Page 354: GJavaDocs

Module 9: State Management

354 Copyright © 2001, DevelopMentor Inc.

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

Page 355: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 355

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

Instance (member)data

Method Parameters

Local (Stack)

Sessions

classclassclassclass foofoofoofoo{{{{private staticprivate staticprivate staticprivate static intintintint a;a;a;a;

classclassclassclass foofoofoofoo{{{{privateprivateprivateprivate intintintint n;n;n;n;

void bar(void bar(void bar(void bar(intintintint a,a,a,a, intintintint b){b){b){b){}}}}

voidvoidvoidvoid quuxquuxquuxquux(){(){(){(){intintintint l;l;l;l;

HttpSessionHttpSessionHttpSessionHttpSession session =session =session =session =req.req.req.req.getSessiongetSessiongetSessiongetSession();();();();

ServletContext getServletContextgetServletContextgetServletContextgetServletContext(((().).).).setAttributesetAttributesetAttributesetAttribute(...)(...)(...)(...)

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

Page 356: GJavaDocs

Module 9: State Management

356 Copyright © 2001, DevelopMentor Inc.

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.

Page 357: GJavaDocs
Page 358: GJavaDocs

Module 9: State Management

358 Copyright © 2001, DevelopMentor Inc.

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

Page 359: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 359

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.

Page 360: GJavaDocs

Module 9: State Management

360 Copyright © 2001, DevelopMentor Inc.

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

Page 361: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 361

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

Page 362: GJavaDocs

Module 9: State Management

362 Copyright © 2001, DevelopMentor Inc.

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

Page 363: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 363

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

Page 364: GJavaDocs

Module 9: State Management

364 Copyright © 2001, DevelopMentor Inc.

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

Page 365: GJavaDocs

Module 9: State Management

Copyright © 2001, DevelopMentor Inc. 365

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!

Page 366: GJavaDocs

Module 9: State Management

366 Copyright © 2001, DevelopMentor Inc.

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

Page 367: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 367

Module 10

EJB Session Beans

Page 368: GJavaDocs

368 Copyright © 2001, DevelopMentor Inc.

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

Page 369: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 369

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.

Page 370: GJavaDocs

Module 10: EJB Session Beans

370 Copyright © 2001, DevelopMentor Inc.

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

Page 371: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 371

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.

Page 372: GJavaDocs

Module 10: EJB Session Beans

372 Copyright © 2001, DevelopMentor Inc.

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

Page 373: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 373

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

Page 374: GJavaDocs

Module 10: EJB Session Beans

374 Copyright © 2001, DevelopMentor Inc.

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).

does not exist

container creates when needed:Class.newInstance()setSessionContext()ejbCreate()

clientexecutesmethod method

executionends

Executing method on behalf of some client request

container destroys:ejbRemove()Object.finalize()

in pool (no identity)waiting to execute method call

Figure 10.1: Lifecycle of a stateless session bean

Page 375: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 375

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.

Page 376: GJavaDocs

Module 10: EJB Session Beans

376 Copyright © 2001, DevelopMentor Inc.

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.

Page 377: GJavaDocs
Page 378: GJavaDocs

Module 10: EJB Session Beans

378 Copyright © 2001, DevelopMentor Inc.

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

Page 379: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 379

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.

Page 380: GJavaDocs

Module 10: EJB Session Beans

380 Copyright © 2001, DevelopMentor Inc.

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

Page 381: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 381

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.

Page 382: GJavaDocs

Module 10: EJB Session Beans

382 Copyright © 2001, DevelopMentor Inc.

does not exist ready

client calls create(…) on home:Class.newInstance()setSessionContext()ejbCreate(…)

Client executesmethod

Method executionendsexecuting

client calls remove()or session times out:ejbRemove()

passive

container passivates:ejbPassivate()

client calls method and container reactivates:ejbActivate()

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-

Page 383: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 383

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.

Page 384: GJavaDocs

Module 10: EJB Session Beans

384 Copyright © 2001, DevelopMentor Inc.

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

Page 385: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 385

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

Page 386: GJavaDocs

Module 10: EJB Session Beans

386 Copyright © 2001, DevelopMentor Inc.

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...

Page 387: GJavaDocs

Module 10: EJB Session Beans

Copyright © 2001, DevelopMentor Inc. 387

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.

Page 388: GJavaDocs

Module 10: EJB Session Beans

388 Copyright © 2001, DevelopMentor Inc.

Summary • Stateless session beans represent procedural model

• Stateful sessions represent conversational model

Page 389: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 389

Module 11

XML-based Web Services

Page 390: GJavaDocs

390 Copyright © 2001, DevelopMentor Inc.

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

Page 391: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 391

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.

Page 392: GJavaDocs

Module 11: XML-based Web Services

392 Copyright © 2001, DevelopMentor Inc.

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

Page 393: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 393

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.

Page 394: GJavaDocs
Page 395: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 395

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.

Page 396: GJavaDocs

Module 11: XML-based Web Services

396 Copyright © 2001, DevelopMentor Inc.

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

Page 397: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 397

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

<?xml version=‘1.0’ ?><ns:student xmlns:ns=‘urn:com:dm:people’>

<name>Kevin Jones</name><age>39</age></ns:student>

Element : {urn:dm:people,student}

Element : {null,name}

Characters : Kevin Jones

Element : {null,age}

Characters : 39

XML Infoset(Abstract model)

XML 1.0 + Namespaces(Concrete syntax)

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

Page 398: GJavaDocs

Module 11: XML-based Web Services

398 Copyright © 2001, DevelopMentor Inc.

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.xmlElement : {urn:com:dm:people,Person}, {urn:dm:people,student}

Element : {schema-ns,string}, {null,name}string : Kevin Jones

Element : {schema-ns, double}, {null,age}double : 39.0

Document : http://www.develop.com/roster.xmlElement : {urn:com:dm:people,Person}, {urn:dm:people,student}

Element : {schema-ns,string}, {null,name}string : Kevin Jones

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'/><xsd:element type= ‘xsd:double' name='age'/>

</xsd:sequence></xsd :complexType ><xsd:element type= ‘tns:Person' name= ‘student'/>

</xsd:schema>

Post-SchemaXML Infoset(Abstract model)

XML 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).

Page 399: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 399

<?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.

Page 400: GJavaDocs

Module 11: XML-based Web Services

400 Copyright © 2001, DevelopMentor Inc.

.NET TypeInformation

COM TypeInformation

DBMS TypeInformation

DirectoryType

Information

JVM TypeInformation

AutomaticSerialization

RemoteMethod

Invocation

SmartEditors

CodeGeneration

GeneralPurpose

Validators

XML Schema

Figure 11.4: The role of XML Schemas

Programmatic type(Class) Schema Type

Programmatic instance(Object) XML Instance

Figure 11.5: Bridging the type system

Page 401: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 401

// new operator instantiates a type,

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

// package definition scopes the structured typepackage com.develop.people// Class definitions describe structured typeclass Person {

String name;short age;…

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

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

Page 402: GJavaDocs

Module 11: XML-based Web Services

402 Copyright © 2001, DevelopMentor Inc.

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

Page 403: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 403

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.

boolean

float

double

decimal

year

month

base64Binary

uriReference

ID

IDREF

ENTITY

NOTATIONQName

IDREFS

ENTITIES

integer

nonPositiveInteger negativeInteger

long

int

short

byte

nonNegativeInteger

unsignedLong

unsignedInt

unsignedShort

unsignedByte

positiveInteger

token

language

NMTOKEN NMTOKENS

Name

NCName

hexBinary

normalizedStringstring

time

date

dateTime

duration

day

yearMonth

monthDay

anySimpleType

anyType all complex types

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.

Page 404: GJavaDocs

Module 11: XML-based Web Services

404 Copyright © 2001, DevelopMentor Inc.

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

Page 405: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 405

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.

<xsd:group name='ProductTypes' ><xsd:choice>

<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' >

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

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

</xsd:sequence>

</xsd:complexType>

Gro

up D

efin

ition

Gro

up

Group Reference

Gro

up

Gro

up

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).

Page 406: GJavaDocs

Module 11: XML-based Web Services

406 Copyright © 2001, DevelopMentor Inc.

<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' />

<p:student xmlns:p=‘urn:com:develop:People' ><age>30</age><height>short</height><name>

<givenName>Barney</givenName><familyName>Rubble</familyName>

</name></p:student>

Global and in schema namespace

Local and in no 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.

Page 407: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 407

<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:transportxmlns: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:transportxmlns: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

Page 408: GJavaDocs
Page 409: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 409

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.

Page 410: GJavaDocs

Module 11: XML-based Web Services

410 Copyright © 2001, DevelopMentor Inc.

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

Page 411: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 411

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.

Page 412: GJavaDocs

Module 11: XML-based Web Services

412 Copyright © 2001, DevelopMentor Inc.

<soap:Envelopexmlns:soap=‘http://schemas.xmlsoap.org/soap/envelope/’soap:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/’ ><soap:Header>

</soap:Header><soap:Body>

</soap:Body></soap:Envelope>

<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>

<t:MyType xmlns:t=‘URI-for-MyTypes’ ><field1>3</field1><field2>Bob</field2>

</t:MyType>

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.

Page 413: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 413

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

<t:Point xmlns:t=‘urn:my:types’><x>23</x><y>34</y>

</t:Point><t:PointArrayxmlns: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>

point = new Point();x=23;y=34;pointArray = new Point[2];

[0].x=3; [0].y=4;[1].x=5; [1].y=6;

pointArraypointArray

pointArraypointArray

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

Page 414: GJavaDocs

Module 11: XML-based Web Services

414 Copyright © 2001, DevelopMentor Inc.

"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

Page 415: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 415

<soap:Envelopexmlns: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>

</soap:Envelope>

<soap:Envelopexmlns: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>

to server

from server

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);

Figure 11.20: SOAP method call

POST /calcs/calcArea HTTP/1.1Content-Type: text/xmlSOAPAction: http://develop.com/calcs#calcAreaContent-Length: nnnn

<soap:Envelopexmlns: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>

</soap:Envelope>200 OKContent-Type: text/xmlContent-Length: nnnn

<soap:Envelopexmlns: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

Page 416: GJavaDocs

Module 11: XML-based Web Services

416 Copyright © 2001, DevelopMentor Inc.

HTTP/1.1 500 Internal Server ErrorContentType: text/xmlContentLength: 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

Page 417: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 417

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.

Page 418: GJavaDocs

Module 11: XML-based Web Services

418 Copyright © 2001, DevelopMentor Inc.

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

Page 419: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 419

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

Page 420: GJavaDocs

Module 11: XML-based Web Services

420 Copyright © 2001, DevelopMentor Inc.

<?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

Page 421: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 421

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.

Page 422: GJavaDocs
Page 423: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 423

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.

Page 424: GJavaDocs

Module 11: XML-based Web Services

424 Copyright © 2001, DevelopMentor Inc.

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

Page 425: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 425

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.

Page 426: GJavaDocs

Module 11: XML-based Web Services

426 Copyright © 2001, DevelopMentor Inc.

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)

Page 427: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 427

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.

NameAddressContact....

RetailHealthFinance...

URLWSDLtModel...

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

servicetModel

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

Page 428: GJavaDocs

Module 11: XML-based Web Services

428 Copyright © 2001, DevelopMentor Inc.

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

Page 429: GJavaDocs
Page 430: GJavaDocs

Module 11: XML-based Web Services

430 Copyright © 2001, DevelopMentor Inc.

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

Page 431: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 431

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).

Namefind_business

find_service

find_binding

find_tModel

get_businessDetail

get_businessDetailExt

get_serviceDetail

get_bindingDetail

get_tModelDetail

DescriptionLocates information about one or more businesses.

Locates services within a registered businessEntity.

Locates bindings within a registered businessService.

Locates one or more tModel information structures.

Gets businessEntity information for one or more businesses.

Gets extended businessEntity information.

Gets full details for a set of registered businessServices.

Gets bindingTemplate information for making service requests.

Gets details for a set of registered tModels.

Figure 11.28: UDDI Inquiry API

<?xml version='1.0' encoding='utf-8'?><s:Envelopexmlns: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

Page 432: GJavaDocs

Module 11: XML-based Web Services

432 Copyright © 2001, DevelopMentor Inc.

<businessListgeneric="1.0" operator="Microsoft Corporation"truncated="false" xmlns="urn:uddi-org:api"><businessInfos>

<businessInfobusinessKey="D2033110-3AAF-11D5-80DC-002035229C64"><name>IBM Corporation</name><descriptionxml: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

Page 433: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 433

<serviceListgeneric="1.0" operator="Microsoft Corporation"truncated="false" xmlns="urn:uddi-org:api"><serviceInfos>

<serviceInfobusinessKey="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

Page 434: GJavaDocs

Module 11: XML-based Web Services

434 Copyright © 2001, DevelopMentor Inc.

<serviceDetailgeneric="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>

<bindingTemplatebindingKey="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>

<tModelInstanceInfotModelKey="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.

Page 435: GJavaDocs

Module 11: XML-based Web Services

Copyright © 2001, DevelopMentor Inc. 435

Name

delete_business

delete_service

delete_binding

delete_tModel

discard_authToken

get_authToken

get_registeredInfo

save_business

save_service

save_binding

save_tModel

Description

Deletes a businessEntity from registry.

Deletes a businessService from registry.

Deletes a bindingTemplate from registry.

Deletes a tModel from registry.

Discards an existing authentication token.

Requests an authentication token from an operator site.

Requests information currently managed by user.

Registers/updates a businessEntity.

Registers/updates a businessService.

Registers/updates a bindingTemplate.

Registers/updates a tModel.

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

Page 436: GJavaDocs

Module 11: XML-based Web Services

436 Copyright © 2001, DevelopMentor Inc.

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

Page 437: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 437

Module 12

Resource Loaders

Page 438: GJavaDocs

438 Copyright © 2001, DevelopMentor Inc.

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

Page 439: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 439

Resource Loaders

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

Page 440: GJavaDocs

Module 12: Resource Loaders

440 Copyright © 2001, DevelopMentor Inc.

Resource Loader Architecture

The Java resource loader architecture is

• Safe

• Dynamic

• Namespace-aware

• Version-aware

• Network-aware

• Usable

• Extensible

Page 441: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 441

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.

Page 442: GJavaDocs

Module 12: Resource Loaders

442 Copyright © 2001, DevelopMentor Inc.

Internal Safety

Class verification guarantees internal consistency

• Strongly-typed bytecodes

• Predictable use of local variable slots

• Predictable use of stack slots

Page 443: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 443

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 -cMethod int add(int, float)

0 iload_11 fload_22 f2i3 iadd4 ireturn

*/

Figure 12.1: Bytecodes are strongly-typed

Page 444: GJavaDocs

Module 12: Resource Loaders

444 Copyright © 2001, DevelopMentor Inc.

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

Page 445: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 445

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.)

Page 446: GJavaDocs

Module 12: Resource Loaders

446 Copyright © 2001, DevelopMentor Inc.

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

Page 447: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 447

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

Page 448: GJavaDocs

Module 12: Resource Loaders

448 Copyright © 2001, DevelopMentor Inc.

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

Page 449: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 449

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

ECL

SCL

AppCL_1 AppCL_2

AppCL_3 AppCL_4

Delegation ofAppCL_4

Figure 12.3: Class Loader Delegation

Page 450: GJavaDocs

Module 12: Resource Loaders

450 Copyright © 2001, DevelopMentor Inc.

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.

Page 451: GJavaDocs
Page 452: GJavaDocs

Module 12: Resource Loaders

452 Copyright © 2001, DevelopMentor Inc.

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

Page 453: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 453

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.0Sealed: trueImplementation-Title: WidgetImplImplementation-Version: 1.4Implementation-Vendor: WidgetMentorSpecification-Title: WidgetSpecification-Version: 1.0.0Specification-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.

Page 454: GJavaDocs

Module 12: Resource Loaders

454 Copyright © 2001, DevelopMentor Inc.

Loading Over a Network

URLClassLoader provides flexible, safe network loading

• HTTP support built-in

• Java security prevents attacks

• URL allows pluggable custom protocols

Page 455: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 455

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.

Page 456: GJavaDocs
Page 457: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 457

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.

Page 458: GJavaDocs

Module 12: Resource Loaders

458 Copyright © 2001, DevelopMentor Inc.

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

Page 459: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 459

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.

Page 460: GJavaDocs

Module 12: Resource Loaders

460 Copyright © 2001, DevelopMentor Inc.

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

Page 461: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 461

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

Page 462: GJavaDocs

Module 12: Resource Loaders

462 Copyright © 2001, DevelopMentor Inc.

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

Page 463: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 463

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 codeThread.currentThread().setContextClassLoader(someLdr);

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

//client codeWidget w = WidgetFactory.getWidget();w.run();

Figure 12.8: Explicitly loading an implementation class

Page 464: GJavaDocs

Module 12: Resource Loaders

464 Copyright © 2001, DevelopMentor Inc.

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.

Page 465: GJavaDocs
Page 466: GJavaDocs

Module 12: Resource Loaders

466 Copyright © 2001, DevelopMentor Inc.

Extending Class Loading

Use custom class loaders to change how code is loaded

• Instrument existing classes

• Access custom attributes

• Generate classes on-the-fly

Page 467: GJavaDocs

Module 12: Resource Loaders

Copyright © 2001, DevelopMentor Inc. 467

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

ClassLoader

2. findClassClass

Repository

1. loadClass

3. defineClass

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.

Page 468: GJavaDocs

Module 12: Resource Loaders

468 Copyright © 2001, DevelopMentor Inc.

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

Page 469: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 469

Module 13

Type Information

Page 470: GJavaDocs

470 Copyright © 2001, DevelopMentor Inc.

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

Page 471: GJavaDocs

Module 13: Type Information

Copyright © 2001, DevelopMentor Inc. 471

Type Information

Java type information is accessible at runtime via Reflection, and is used to develop generic services.

Page 472: GJavaDocs

Module 13: Type Information

472 Copyright © 2001, DevelopMentor Inc.

Type Information

Languages and platforms are type systems

• What is your name?

• What do you consist of?

• What can you do?

Page 473: GJavaDocs

Module 13: Type Information

Copyright © 2001, DevelopMentor Inc. 473

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.

Page 474: GJavaDocs

Module 13: Type Information

474 Copyright © 2001, DevelopMentor Inc.

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

Page 475: GJavaDocs

Module 13: Type Information

Copyright © 2001, DevelopMentor Inc. 475

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.

Object

Class

Field

Method

Constructor

Array

Package

getClass

getField

getMethod

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

Page 476: GJavaDocs

Module 13: Type Information

476 Copyright © 2001, DevelopMentor Inc.

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 allpublic int getModifiers();public Class getDeclaringClass();

//Fieldpublic String getName();public Class getTypes();

//Methodpublic Class getReturnType();

//Method and Constructorpublic Class[] getParameterTypes();public Class[] getExceptionTypes();

Figure 13.3: Interrogating Fields, Methods, and Constructors

Page 477: GJavaDocs
Page 478: GJavaDocs

Module 13: Type Information

478 Copyright © 2001, DevelopMentor Inc.

Reflective Modification

Can use reflection package to dynamically modify objects

• Load classes

• Set fields

• Invoke methods

• Call constructors

• Ignore protection modifiers

Page 479: GJavaDocs

Module 13: Type Information

Copyright © 2001, DevelopMentor Inc. 479

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 AirplaneFactorythrows 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.

Page 480: GJavaDocs

Module 13: Type Information

480 Copyright © 2001, DevelopMentor Inc.

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

Page 481: GJavaDocs
Page 482: GJavaDocs

Module 13: Type Information

482 Copyright © 2001, DevelopMentor Inc.

Dynamic Proxies

DPs are classes generated from type information

• Implement a set of interfaces

• Forward to an InvocationHandler

• Implement AOP dynamically

Page 483: GJavaDocs

Module 13: Type Information

Copyright © 2001, DevelopMentor Inc. 483

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.

Client AccountAccountAuditor

deposit

withdrawinvoke

Client AccountAuditing

InvocationHandler

deposit

withdrawinvoke

Dyn.Proxy invoke

Figure 13.6: Intercepting Method Calls with a Proxy

Page 484: GJavaDocs

Module 13: Type Information

484 Copyright © 2001, DevelopMentor Inc.

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.

Page 485: GJavaDocs
Page 486: GJavaDocs

Module 13: Type Information

486 Copyright © 2001, DevelopMentor Inc.

Type-driven services in J2EE

J2EE == containers plus type-driven services

• Object / relational mapping

• Serialization

• Remoting

• Interop, particularly XML

• EJB: Aspects Simplified

Page 487: GJavaDocs

Module 13: Type Information

Copyright © 2001, DevelopMentor Inc. 487

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.

Page 488: GJavaDocs

Module 13: Type Information

488 Copyright © 2001, DevelopMentor Inc.

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

Page 489: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 489

Module 14

EJB Entities

Page 490: GJavaDocs

490 Copyright © 2001, DevelopMentor Inc.

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

Page 491: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 491

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.

Page 492: GJavaDocs

Module 14: EJB Entities

492 Copyright © 2001, DevelopMentor Inc.

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

Page 493: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 493

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.

EJB Object

LegacyApplication

remote

i/f

CMP bean

Bean fields

DeploymentDescriptor

Managed field listMapping details

SQL

PersistenceLayer

Container writesdata access code

EJB Objectremote

i/f

BMP bean

Bean fields

SQLPersistenceLayer

Bean writesdata access code

Used to build

Figure 14.1: Entity persistence models

Page 494: GJavaDocs

Module 14: EJB Entities

494 Copyright © 2001, DevelopMentor Inc.

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.

machine 1

machine 2

session

ref 1

session

ref 4

Tx isolationprovidedby container

Tx isolationprovidedby database

EJB Objectrem

i/fbean

session

ref 3

session

ref 2

EJB Objectrem

i/fbean

EJB Objectrem

i/fbean Other app

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.

Page 495: GJavaDocs
Page 496: GJavaDocs

Module 14: EJB Entities

496 Copyright © 2001, DevelopMentor Inc.

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

Page 497: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 497

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.

Page 498: GJavaDocs

Module 14: EJB Entities

498 Copyright © 2001, DevelopMentor Inc.

import javax.ejb.*;import java.rmi.*;

public interface CustomerEntityHome extends EJBHome{// Optional - If no create() then entity data must be// created by other meanspublic 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{...// Requiredpublic CustomerEntity findByPrimaryKey(

CustomerEntityPK pk)throws FinderException, RemoteException;

// Optional// Can return java.util.Collection for Java2-only clientspublic Enumeration findWhereAgeGreaterThan(int age)

throws FinderException, RemoteException;...

}

Figure 14.5: Finding an entity via its home interface

Page 499: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 499

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)

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.

Page 500: GJavaDocs

Module 14: EJB Entities

500 Copyright © 2001, DevelopMentor Inc.

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 onlypublic 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 onlySystem.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

Page 501: GJavaDocs
Page 502: GJavaDocs

Module 14: EJB Entities

502 Copyright © 2001, DevelopMentor Inc.

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

Page 503: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 503

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.

Page 504: GJavaDocs

Module 14: EJB Entities

504 Copyright © 2001, DevelopMentor Inc.

Pool

session

ref 1

session

ref 4

session

ref 3

session

ref 2

EJB Objectrem

i/f

Primary key

Bean (with identity)

Bean (no identity)

EJB Objectrem

i/f

Primary key

Bean (with identity)

EJB Objectrem

i/f

Primary key

Bean (no identity)Bean

(no identity)Bean (no identity)

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.

Page 505: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 505

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

Page 506: GJavaDocs

Module 14: EJB Entities

506 Copyright © 2001, DevelopMentor Inc.

interface that contains the ejbSetEntityContext(), ejbUnsetEntityContext(), ejbActivate(), ejbPassivate(), ejbLoad() and ejbStore() methods must always be implemented by the bean class.

does not exist

container creates:Class.newInstance()setEntityContext()

methodexecutes

container destroys:unsetEntityContext()Object.finalize()

create() called on home interface:ejbCreate()ejbPostCreate()

or container activates:ejbActivate()

remove() called on home/remote interface:ejbRemove()

or container passivates:ejbPassivate()

ready(identity)

container loads data:ejbLoad()or container saves data:ejbStore()

container finds:ejbFindByxxx()

(BMP only)

in pool(no identity)

ejbyxxx() home method executes (EJB 2 only)

ejbSelect()(EJB 2 CMP only)

Figure 14.10: Entity bean class lifecycle

Page 507: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 507

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.

Page 508: GJavaDocs

Module 14: EJB Entities

508 Copyright © 2001, DevelopMentor Inc.

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

Page 509: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 509

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 CustomerEntityBeanextends EntityBean {

public int id;public String name;public int age;public String getName(){return name;}public void setName(String n){name=n;}…} // primary key

public class CustomerEntityPK … {public int id;…}

<ejb-jar><enterprise-beans>

<entity><!-- managed fields, primary key --></entity>

</enterprise-beans></ejb-jar> <container-specific>

<!-- All details of dependent objects,entity relationships,dependent object relationship andmapping of managedfields/relationships iscontainer-specific -->

</container-specific >

Containerdeployment tool

Container-generateddata access code

Deployer

Figure 14.11: EJB 1.1 CMP deployment

remote

Interface

public class CustomerEntityBean … {public int id;public String name;public int age;public String getName(){return name;}public void setName(String n){name=n;}…}

CUSTOMER table CNAME CADDRESS CAGE

John Smith 1 Hill View, Cheltenham 47

Mary Barnes34 Beacon Rd, Gloucester 22

CID

0001

0002

Kevin Jones 3 Sheep St, Wellington 390003

Instance of CustomerEntityPKid=0002

Container-generateddata access code

EntityContext.getPrimaryKey()

Container-generatedinterposer

Figure 14.12: EJB 1.1 CMP at runtime

Page 510: GJavaDocs

Module 14: EJB Entities

510 Copyright © 2001, DevelopMentor Inc.

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.

Page 511: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 511

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 interfacepublic 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 interfacepublic 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 interfacepublic 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.

Page 512: GJavaDocs

Module 14: EJB Entities

512 Copyright © 2001, DevelopMentor Inc.

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.

Page 513: GJavaDocs
Page 514: GJavaDocs

Module 14: EJB Entities

514 Copyright © 2001, DevelopMentor Inc.

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?

Page 515: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 515

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

Page 516: GJavaDocs

Module 14: EJB Entities

516 Copyright © 2001, DevelopMentor Inc.

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.

<ejb-jar><enterprise-beans>

<entity><!-- managed fields, primary key --></entity>

</enterprise-beans><dependents>

…</dependents><relationships>

…</relationships>

</ejb-jar><container-specific>

<!-- All details ofmapping managedfields/relationshipsis stillcontainer-specific -->

</container-specific >Persistence Managerdeployment tool

Persistence Manager-generateddata access code

Deployer

public abstract class CustomerEntityBeanextends EntityBean {

public abstract String getName();public abstract void setName(String n);public abstract Address getAddress();public abstract void setAddress(Address a);…} public abstract class Address … {

public abstract String getStreet();public abstract void setStreet(String s);…}

// primary keypublic class CustomerEntityPK … {public int id;…}

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.

Page 517: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 517

public abstract class CustomerEntityBeanextends EntityBean {

public abstract Address getAddress();public abstract void setAddress(Address a);public abstract int getId();public abstract void setId(int id);public abstract String getName();public abstract void setName(String n);…}

public abstract class Addressimplements Serializable {

public abstract String getStreet();public abstract void setStreet(String s);…}

public class RealCustomerEntityBeanextends 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) {…}…}

public class RealAddressextends Address {

public String getStreet() {…}public void setStreet(String s) {…}…}

CUSTOMER table

CNAME CADDRESS CAGE

John Smith 1 Hill View, Cheltenham 47

Mary Barnes 34 Beacon Rd, Gloucester 22

CID

0001

0002

Kevin Jones 3 Sheep St, Wellington 390003

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.

Page 518: GJavaDocs

Module 14: EJB Entities

518 Copyright © 2001, DevelopMentor Inc.

remote

Interface

CNAME CADDRESS CAGE

John Smith 1 Hill View, Cheltenham 47

Mary Barnes34 Beacon Rd, Gloucester 22

CID

0001

0002

Kevin Jones 3 Sheep St, Wellington 390003

public abstract class CustomerEntityBean … {public abstract String getName();public abstract void setName(String n);…} public abstract class Address … {

public abstract String getStreet();public abstract void setStreet(String s);…}

Persistence manager-generateddata access code

Instance of CustomerEntityPKid=0002

EntityContext.getPrimaryKey()

Container-generatedinterposer

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.

Page 519: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 519

import javax.ejb.*;

// Only deltas from EJB CMP 1.1 shownpublic abstract class CustomerEntityBean implementsEntityBean {...// Methods corresponding to create() in home interfacepublic 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 interfacepublic 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 fieldspublic 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

Page 520: GJavaDocs

Module 14: EJB Entities

520 Copyright © 2001, DevelopMentor Inc.

<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

Page 521: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 521

<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.

Page 522: GJavaDocs

Module 14: EJB Entities

522 Copyright © 2001, DevelopMentor Inc.

<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.

Page 523: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 523

public abstract class CustomerEntityBean implementsEntityBean {...public int ejbHomeNumAccounts (int bal ){

Collection col = ejbSelectAccouts(bal);return col.size();

}...// Abstract getter/setter methods for managed fieldspublic 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 fieldspublic abstract int getBalance();...

}

Figure 14.23: EJB QL example code

Page 524: GJavaDocs

Module 14: EJB Entities

524 Copyright © 2001, DevelopMentor Inc.

<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

Page 525: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 525

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.

Page 526: GJavaDocs

Module 14: EJB Entities

526 Copyright © 2001, DevelopMentor Inc.

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

Page 527: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 527

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.

Page 528: GJavaDocs

Module 14: EJB Entities

528 Copyright © 2001, DevelopMentor Inc.

import javax.ejb.*;

// Only CMP deltas shownpublic 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 CustomerEntityPKejbFindByPrimaryKey(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.

Page 529: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 529

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.

Page 530: GJavaDocs
Page 531: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 531

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.

Page 532: GJavaDocs

Module 14: EJB Entities

532 Copyright © 2001, DevelopMentor Inc.

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

Page 533: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 533

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?

Page 534: GJavaDocs

Module 14: EJB Entities

534 Copyright © 2001, DevelopMentor Inc.

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?

Page 535: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 535

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

Page 536: GJavaDocs

Module 14: EJB Entities

536 Copyright © 2001, DevelopMentor Inc.

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.

Page 537: GJavaDocs

Module 14: EJB Entities

Copyright © 2001, DevelopMentor Inc. 537

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

Page 538: GJavaDocs
Page 539: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 539

Module 15

XSLT

Page 540: GJavaDocs

540 Copyright © 2001, DevelopMentor Inc.

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

Page 541: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 541

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.

Page 542: GJavaDocs

Module 15: XSLT

542 Copyright © 2001, DevelopMentor Inc.

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

Page 543: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 543

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.

Input XMLinfoset

XSL Transform(also an XML

infoset)

Output(text or XML

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.

Page 544: GJavaDocs

Module 15: XSLT

544 Copyright © 2001, DevelopMentor Inc.

Input XMLInfoset

Transform

OutputXSLTProcessor

Figure 15.2: Input and output of an XSLT Processor

Page 545: GJavaDocs
Page 546: GJavaDocs

Module 15: XSLT

546 Copyright © 2001, DevelopMentor Inc.

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

Page 547: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 547

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"?><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>

<?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>

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

Page 548: GJavaDocs

Module 15: XSLT

548 Copyright © 2001, DevelopMentor Inc.

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.

Page 549: GJavaDocs
Page 550: GJavaDocs

Module 15: XSLT

550 Copyright © 2001, DevelopMentor Inc.

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

Page 551: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 551

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

Page 552: GJavaDocs

Module 15: XSLT

552 Copyright © 2001, DevelopMentor Inc.

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.

<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>

<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

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

Page 553: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 553

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></xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><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.

Page 554: GJavaDocs

Module 15: XSLT

554 Copyright © 2001, DevelopMentor Inc.

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></xsl:template>

</xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><people>

<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>

Page 555: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 555

<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.

Page 556: GJavaDocs

Module 15: XSLT

556 Copyright © 2001, DevelopMentor Inc.

<?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.

Page 557: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 557

<?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></xsl:for-each>

</people></xsl:template>

</xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><people>

<adult>Martin</adult><adult>Hayley</adult><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.

Page 558: GJavaDocs

Module 15: XSLT

558 Copyright © 2001, DevelopMentor Inc.

<?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>

<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>

Attributevalue template

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).

Page 559: GJavaDocs
Page 560: GJavaDocs

Module 15: XSLT

560 Copyright © 2001, DevelopMentor Inc.

XSLT syntax (2)

Working with multiple templates

• Calling named templates

• Applying templates rules

• Variables

• Parameters

• Copying node-sets

• Identity transform

Page 561: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 561

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>

</xsl:template></xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><people>

<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.

Page 562: GJavaDocs

Module 15: XSLT

562 Copyright © 2001, DevelopMentor Inc.

<?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>

</xsl:for-each></xsl:template></xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><people>

<person>Martin</person><person>Hayley</person>

</people>

Figure 15.12: xsl:with-param example

<?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>

</xsl:for-each></xsl:template></xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><people>

<person>Martin</person></people>

java org.apache.xalan.xslt.Process -IN input.xml -XSL param.xsl-PARAM numyears 32

Figure 15.13: xsl:param example

Page 563: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 563

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

Page 564: GJavaDocs

Module 15: XSLT

564 Copyright © 2001, DevelopMentor Inc.

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 peopleelement 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.

Page 565: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 565

<?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></xsl:template>

</xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><people>

<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 overthe lazy <noun>dog</noun></p></chapter></book> book

chapter

title p

text noun text noun text noun

book

chapter

title p

text noun text noun text noun

Figure 15.16: irregular input

Page 566: GJavaDocs

Module 15: XSLT

566 Copyright © 2001, DevelopMentor Inc.

<?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>

</xsl:template></xsl:transform>

<html><body><p>Testing your <b>typewriter</b>The quick brown <b>fox</b> jumped overthe 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.

Page 567: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 567

<?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>

</xsl:transform> <?xml version="1.0" encoding="UTF-8"?><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

Page 568: GJavaDocs

Module 15: XSLT

568 Copyright © 2001, DevelopMentor Inc.

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

Page 569: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 569

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...

Page 570: GJavaDocs

Module 15: XSLT

570 Copyright © 2001, DevelopMentor Inc.

<?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 ></xsl:template>

</xsl:transform>

<?xml version="1.0" encoding="UTF-8"?><person><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

Page 571: GJavaDocs

Module 15: XSLT

Copyright © 2001, DevelopMentor Inc. 571

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

Page 572: GJavaDocs

Module 15: XSLT

572 Copyright © 2001, DevelopMentor Inc.

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

Page 573: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 573

Module 16

Platform Security

Page 574: GJavaDocs

574 Copyright © 2001, DevelopMentor Inc.

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

Page 575: GJavaDocs

Module 16: Platform Security

Copyright © 2001, DevelopMentor Inc. 575

Platform Security

The Java virtual machine protects all sensitive operations through a flexible security manager.

Page 576: GJavaDocs

Module 16: Platform Security

576 Copyright © 2001, DevelopMentor Inc.

SecurityManager

The SecurityManager checks sensitive operations

• Originally an abstract base class

• Since Java 2, delegates to AccessController

• Most server processes should activate security

Page 577: GJavaDocs

Module 16: Platform Security

Copyright © 2001, DevelopMentor Inc. 577

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");

//...

class GoodClass {FileOutputStream fos =new FileOutputStream("candy.bar");

//...

FileSystem

SecurityManager

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

Page 578: GJavaDocs

Module 16: Platform Security

578 Copyright © 2001, DevelopMentor Inc.

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

Page 579: GJavaDocs

Module 16: Platform Security

Copyright © 2001, DevelopMentor Inc. 579

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 ClassLoaderprotected 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

Page 580: GJavaDocs

Module 16: Platform Security

580 Copyright © 2001, DevelopMentor Inc.

Policy

The system policy assigns permissions to code sources

• Abstract Policy class

• Reference implementation configured by policy files

• Grant blocks are additive

Page 581: GJavaDocs

Module 16: Platform Security

Copyright © 2001, DevelopMentor Inc. 581

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.

Page 582: GJavaDocs

Module 16: Platform Security

582 Copyright © 2001, DevelopMentor Inc.

SecureClassLoader 4. permit the call if everyset of permissionsimplies p

Policy object

checkPermission(p)

implies?p

implies?p

implies?p

implies?p

grant ---- {---;---;

};

codesource permissions

Policy AccessController

1. get array ofclasses on callstack with SM'sgetCallContext

2. get array of code sourceswith class'sgetProtectionDomain

3. get array of permissionsfrom the protection domain

caches codesource topermissions mapping in aProtectionDomain

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.

Page 583: GJavaDocs
Page 584: GJavaDocs

Module 16: Platform Security

584 Copyright © 2001, DevelopMentor Inc.

Default Policy

Located in JRE/lib/security/java.policy

• Very restrictive

• Must be activated

• Settings can be augmented or replaced

Page 585: GJavaDocs

Module 16: Platform Security

Copyright © 2001, DevelopMentor Inc. 585

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 policyjava -Djava.security.manager

-Djava.security.policy=my.policySomeApp

rem "==" replaces default policy with my.policyjava -Djava.security.manager

-Djava.security.policy==my.policySomeApp

Figure 16.7: Choosing the Policy from the Command Line

Page 586: GJavaDocs

Module 16: Platform Security

586 Copyright © 2001, DevelopMentor Inc.

Permissions

The permissions listed in the Policy are Java classes

• Represent secured operation

• Name + action + target

• Easy to add custom permissions

Page 587: GJavaDocs

Module 16: Platform Security

Copyright © 2001, DevelopMentor Inc. 587

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.

Meaning

all files in current directory

all files in current and subdirectories

all files

any value at current level in hierarchy

Wildcard

*-<<ALL FILES>>

*

Permission

FilePermission

FilePermission

FilePermission

PropertyPermission

any value at current level in hierarchy*RuntimePermission

any value in left of DNS, e.g. *.sun.com*SocketPermission

range of port numbers-, #-, #-#SocketPermission

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.

Page 588: GJavaDocs

Module 16: Platform Security

588 Copyright © 2001, DevelopMentor Inc.

/*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 finalif (!(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.

Page 589: GJavaDocs
Page 590: GJavaDocs

Module 16: Platform Security

590 Copyright © 2001, DevelopMentor Inc.

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

Page 591: GJavaDocs

Module 16: Platform Security

Copyright © 2001, DevelopMentor Inc. 591

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

Page 592: GJavaDocs

Module 16: Platform Security

592 Copyright © 2001, DevelopMentor Inc.

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

Page 593: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 593

Module 17

Java Distributed Security

Page 594: GJavaDocs

594 Copyright © 2001, DevelopMentor Inc.

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

Page 595: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 595

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.

Page 596: GJavaDocs

Module 17: Java Distributed Security

596 Copyright © 2001, DevelopMentor Inc.

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

Page 597: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 597

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.

Page 598: GJavaDocs

Module 17: Java Distributed Security

598 Copyright © 2001, DevelopMentor Inc.

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

Page 599: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 599

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.1Host: 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 UnauthorizedWWW-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.1Host: fooAuthorization: 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

Page 600: GJavaDocs

Module 17: Java Distributed Security

600 Copyright © 2001, DevelopMentor Inc.

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 UnauthorizedWWW-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.

Page 601: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 601

GET /secureApp/resource1 HTTP/1.1Host: fooAuthorization: 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.

Page 602: GJavaDocs

Module 17: Java Distributed Security

602 Copyright © 2001, DevelopMentor Inc.

HTTP/1.1 401 UnauthorizedWWW-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>

Page 603: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 603

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.

Page 604: GJavaDocs

Module 17: Java Distributed Security

604 Copyright © 2001, DevelopMentor Inc.

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

Page 605: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 605

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

Page 606: GJavaDocs

Module 17: Java Distributed Security

606 Copyright © 2001, DevelopMentor Inc.

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

Page 607: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 607

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-suitelist) Server Hello

(random# + cipher-suite+ server cert+ client cert request*)

Client Finish(client cert*,encrypted pre-master secret,cert verification code*,change cipher specMessage AuthenticationCode)

Server Finish(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

Page 608: GJavaDocs

Module 17: Java Distributed Security

608 Copyright © 2001, DevelopMentor Inc.

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

Page 609: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 609

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(newcom.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 = newInputStreamReader(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

Page 610: GJavaDocs
Page 611: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 611

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

Page 612: GJavaDocs

Module 17: Java Distributed Security

612 Copyright © 2001, DevelopMentor Inc.

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?

Page 613: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 613

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.

HTTP(S) request

Web application

web.xml Servlet

check transport

requirements

check authenticationrequirements

check authorizationrequirements

check ifsecured resource

401 Unauthorized

403 Access Denied

200 OK

Figure 17.9: Servlet container uses web application descriptor to make

security decisions

Page 614: GJavaDocs

Module 17: Java Distributed Security

614 Copyright © 2001, DevelopMentor Inc.

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

Page 615: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 615

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.

Page 616: GJavaDocs

Module 17: Java Distributed Security

616 Copyright © 2001, DevelopMentor Inc.

<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

Page 617: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 617

<!-- 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.

Page 618: GJavaDocs

Module 17: Java Distributed Security

618 Copyright © 2001, DevelopMentor Inc.

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

Page 619: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 619

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.

Page 620: GJavaDocs

Module 17: Java Distributed Security

620 Copyright © 2001, DevelopMentor Inc.

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

Page 621: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 621

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

Page 622: GJavaDocs

Module 17: Java Distributed Security

622 Copyright © 2001, DevelopMentor Inc.

<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.

Page 623: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 623

<web-app>...<resource-ref>

<!-- Refers to some server resource pre-configuredwith 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

Page 624: GJavaDocs

Module 17: Java Distributed Security

624 Copyright © 2001, DevelopMentor Inc.

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

Page 625: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 625

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.

Page 626: GJavaDocs

Module 17: Java Distributed Security

626 Copyright © 2001, DevelopMentor Inc.

<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.

Page 627: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 627

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 omittedreturn 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 timeoutreturn 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);HttpURLConnectioncon=(HttpURLConnection)url.openConnection();con.connect();

Figure 17.21: Client use of the hash class

Page 628: GJavaDocs

Module 17: Java Distributed Security

628 Copyright © 2001, DevelopMentor Inc.

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) //proceedelse {

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

Page 629: GJavaDocs
Page 630: GJavaDocs

Module 17: Java Distributed Security

630 Copyright © 2001, DevelopMentor Inc.

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

Page 631: GJavaDocs

Module 17: Java Distributed Security

Copyright © 2001, DevelopMentor Inc. 631

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,TellerSessionHome.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.

Page 632: GJavaDocs

Module 17: Java Distributed Security

632 Copyright © 2001, DevelopMentor Inc.

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

Page 633: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 633

Module 18

Tag Libraries

Page 634: GJavaDocs

634 Copyright © 2001, DevelopMentor Inc.

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

Page 635: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 635

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.

Page 636: GJavaDocs

Module 18: Tag Libraries

636 Copyright © 2001, DevelopMentor Inc.

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

Page 637: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 637

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.

Page 638: GJavaDocs

Module 18: Tag Libraries

638 Copyright © 2001, DevelopMentor Inc.

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.

Page 639: GJavaDocs
Page 640: GJavaDocs

Module 18: Tag Libraries

640 Copyright © 2001, DevelopMentor Inc.

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

Page 641: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 641

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>

This tags's body

</a:someTag>

Start of Tag

Tag's 'body'

End of Tag

Figure 18.2: A JSP containing tags

Page 642: GJavaDocs

Module 18: Tag Libraries

642 Copyright © 2001, DevelopMentor Inc.

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

Page 643: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 643

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.

// TagSupport

// 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 ){}

// tag interface

int doStartTag()

int doEndTag()

Tag getParent()void setParent(Tag t)

void release()

void setPageContext(PageContext pc)

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

Page 644: GJavaDocs

Module 18: Tag Libraries

644 Copyright © 2001, DevelopMentor Inc.

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.

Page 645: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 645

<%@ 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 pageContextJspWriter out = pageContext.getOut();// output any HTMLreturn 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.

Page 646: GJavaDocs

Module 18: Tag Libraries

646 Copyright © 2001, DevelopMentor Inc.

<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.

Page 647: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 647

JSP engine sees tag (<simple: tagId…>)

Instantiates a variable of correct typefrom tld file(com.develop.taglib.Simple)

Sets the instance's parent, id and anyother attributes (eg 'secondname’)

Calls instance's doStartTag method

Calls instance's doEndTag method

Calls instance's release method (I'mfinished with this instance)

Initialises tag instance withpageContext

Tag instance does its work

Figure 18.6: Flow of Control for a Simple Tag

Page 648: GJavaDocs

Module 18: Tag Libraries

648 Copyright © 2001, DevelopMentor Inc.

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

Page 649: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 649

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.

Page 650: GJavaDocs

Module 18: Tag Libraries

650 Copyright © 2001, DevelopMentor Inc.

Engine sees (<simple:withbody>)

… As before…

doAfterBody called

doAfterBody returns SKIP_BODYprocessing continues at next line

doAfterBody returns EVAL_BODY_AGAINbody is re-evaluated

Calls instance's doStartTag methodwhich returns EVAL_BODY_INCLUDE

Figure 18.9: Iteration Tag Flow

Page 651: GJavaDocs
Page 652: GJavaDocs

Module 18: Tag Libraries

652 Copyright © 2001, DevelopMentor Inc.

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

Page 653: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 653

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.

Page 654: GJavaDocs

Module 18: Tag Libraries

654 Copyright © 2001, DevelopMentor Inc.

// derives from JSPWritervoid 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>

The body of thetag</simple:tagWithBody>

<simple:tagWithBody><%= bean.getName() %>

</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.

Page 655: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 655

<%@ 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>

<attribute><name>id</name><required>true</required>

</attribute>

<attribute><name>secondname</name><required>false</required>

</attribute></tag>

public class WithBody extends BodyTagSupport{

public int doStartTag() throws JspException{

return EVAL_BODY_BUFFERED;}

public int doAfterBody() throws JspException{

// access BodyContent// and process itreturn 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.

Page 656: GJavaDocs

Module 18: Tag Libraries

656 Copyright © 2001, DevelopMentor Inc.

Engine sees (<simple:withbody>)

… As before…

Empty BodyContent object created

doInitBody called

doAfterBody called

doAfterBody returns SKIP_BODYprocessing continues at next line

doAfterBody returnsEVAL_BODY_BUFFEREDbody is re-evaluated

Calls instance's doStartTag method whichreturns EVAL_BODY_BUFFERED

Body evaluated and BodyContentinitialized

Figure 18.14: Flow of Control for a Body Tag

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();

<tag:parentTag>Hello World

</tag:parentTag

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

Page 657: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 657

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.

Page 658: GJavaDocs

Module 18: Tag Libraries

658 Copyright © 2001, DevelopMentor Inc.

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())

Page 659: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 659

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.

Page 660: GJavaDocs

Module 18: Tag Libraries

660 Copyright © 2001, DevelopMentor Inc.

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();}

<tag:parentTag><tag:childTag/></tag:parentTag>

Figure 18.16: Example of Nested Tag showing the usage and the generated

code.

Page 661: GJavaDocs
Page 662: GJavaDocs

Module 18: Tag Libraries

662 Copyright © 2001, DevelopMentor Inc.

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());

Page 663: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 663

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()).

Page 664: GJavaDocs
Page 665: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 665

Creating Script Objects With Tags

Tags can be used to create Java objects. These objects can be used after the tag has finished processing

Page 666: GJavaDocs

Module 18: Tag Libraries

666 Copyright © 2001, DevelopMentor Inc.

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

Page 667: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 667

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.

Page 668: GJavaDocs

Module 18: Tag Libraries

668 Copyright © 2001, DevelopMentor Inc.

<tag><name> rsScriptVar </name>

<tagclass>com.develop.taglib. RsScriptVar </tagclass><teiclass>com.develop.taglib.ScriptVarTEI</teiclass>

</tag>public class ScriptVarTEI extends TagExtraInfo

{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;}

}

<%@ taglib uri="/simpletags.tld" prefix="simple" %>Some HTML

<simple:rsScriptVar id="rs" ><%= rs.getString(1) %>

</simple: rsScriptVar >Some more HTML

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.

Page 669: GJavaDocs

Module 18: Tag Libraries

Copyright © 2001, DevelopMentor Inc. 669

VariableInfo info = new VariableInfo( data.getId(),

"java.sql.ResultSet",

true,VariableInfo.NESTED );

[] back = { info };

// ----------------------------------------

<quux:foo … > AT_BEGIN and NESTED

</quux:foo> AT_END

VariableInfo info = new VariableInfo( data.getId(),

"java.sql.ResultSet",

true,

VariableInfo.NESTED );

// ----------------------------------------

<quux:foo … > AT_BEGIN and NESTED

</quux:foo> AT_END

Figure 18.20: Specifying when a script variable is available

Page 670: GJavaDocs

Module 18: Tag Libraries

670 Copyright © 2001, DevelopMentor Inc.

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

Page 671: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 671

Module 19

Java Messaging

Page 672: GJavaDocs

672 Copyright © 2001, DevelopMentor Inc.

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

Page 673: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 673

Messaging

Standard RPC mechanisms have issues. Messaging offers a much more flexible communication alternative.

Page 674: GJavaDocs

Module 19: Java Messaging

674 Copyright © 2001, DevelopMentor Inc.

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

Page 675: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 675

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

add method

stub

Method: addParams: 5(long),10(long)

Return: 15(long)

add methodskeleton

Response message

long I = add(5,10);

public long add(long l1,long l2) {

return l1+l2;}

Request 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

Page 676: GJavaDocs

Module 19: Java Messaging

676 Copyright © 2001, DevelopMentor Inc.

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.

Page 677: GJavaDocs
Page 678: GJavaDocs

Module 19: Java Messaging

678 Copyright © 2001, DevelopMentor Inc.

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

Page 679: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 679

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 deliveryinfo used by system

Application-levelproperties

Payload - the request, Response or event

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

Page 680: GJavaDocs

Module 19: Java Messaging

680 Copyright © 2001, DevelopMentor Inc.

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.

Queue

sender

Message Message Message

sender

receiver

receiver

receiver

Figure 19.3: Point-to-point messaging

Page 681: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 681

Topic

publisher

Message Message Message

publisher

durable subscriber(attached)

transient subscriber(attached)

transient subscriber(detached)

durable subscriber(detached)

Delivered atre-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

Page 682: GJavaDocs

Module 19: Java Messaging

682 Copyright © 2001, DevelopMentor Inc.

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.

Page 683: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 683

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.

Page 684: GJavaDocs

Module 19: Java Messaging

684 Copyright © 2001, DevelopMentor Inc.

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

Page 685: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 685

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.

Page 686: GJavaDocs

Module 19: Java Messaging

686 Copyright © 2001, DevelopMentor Inc.

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

Page 687: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 687

Figure 19.5 illustrates the JMS objects and their relationships.

ConnectionFactory

Destination

Connection

Session

createsMessageProducer

MessageConsumer

creates

creates based on

based oncreates

sync consume(polling)

produce

Administered Objects found via JNDI but created and configured via a provider-specific technique

MessageListenerasyncconsume(callback)

async consume(callback)

Message

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();

}

Page 688: GJavaDocs

Module 19: Java Messaging

688 Copyright © 2001, DevelopMentor Inc.

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");

Page 689: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 689

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

Page 690: GJavaDocs

Module 19: Java Messaging

690 Copyright © 2001, DevelopMentor Inc.

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

Page 691: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 691

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.

MessageProducer send/publish method.Time message was sent/published. Not the time it was actually transmitted

JMSTimestamp

Specified before MessageProducersend/publish method called.

Used to link messages together. Application-specific.

JMSCorrelationID

Specified before MessageProducersend/publish method called.

Used to specify a response destination if one is required. Response is not mandatory.

JMSReplyTo

Specified before MessageProducersend/publish method called.

Message type identifier. Could be used as key to the message definition in some type repository.

JMSType

Set by provider.Message has been redelivered and may have been seen before.

JMSRedelivered

Generated by provider when MessageProducer send/publish method called

Unique id Format of “ID:xxx”. Specified by and limited to one provider.

JMSMessageID

Specified in MessageProducersend/publish method

How quickly it gets where it’s going.0 – 4 (normal), 5 – 9 (expedited).

JMSPriority

Specified in MessageProducersend/publish method

Message expiry in ms at send time. 0 means no expiry. System silently removes.

JMSExpiration

Specified in MessageProducersend/publish method

NON-PERSISTENT (not reliable, at most once, faster).PERSISTENT (reliable, only once, slower).

JMSDeliveryMode

Destination that MessageProducer was based on

Message destination.JMSDestination

Set byMeaningName

MessageProducer send/publish method.Time message was sent/published. Not the time it was actually transmitted

JMSTimestamp

Specified before MessageProducersend/publish method called.

Used to link messages together. Application-specific.

JMSCorrelationID

Specified before MessageProducersend/publish method called.

Used to specify a response destination if one is required. Response is not mandatory.

JMSReplyTo

Specified before MessageProducersend/publish method called.

Message type identifier. Could be used as key to the message definition in some type repository.

JMSType

Set by provider.Message has been redelivered and may have been seen before.

JMSRedelivered

Generated by provider when MessageProducer send/publish method called

Unique id Format of “ID:xxx”. Specified by and limited to one provider.

JMSMessageID

Specified in MessageProducersend/publish method

How quickly it gets where it’s going.0 – 4 (normal), 5 – 9 (expedited).

JMSPriority

Specified in MessageProducersend/publish method

Message expiry in ms at send time. 0 means no expiry. System silently removes.

JMSExpiration

Specified in MessageProducersend/publish method

NON-PERSISTENT (not reliable, at most once, faster).PERSISTENT (reliable, only once, slower).

JMSDeliveryMode

Destination that MessageProducer was based on

Message destination.JMSDestination

Set byMeaningName

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().

Page 692: GJavaDocs

Module 19: Java Messaging

692 Copyright © 2001, DevelopMentor Inc.

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

Page 693: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 693

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

Page 694: GJavaDocs

Module 19: Java Messaging

694 Copyright © 2001, DevelopMentor Inc.

...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

Page 695: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 695

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.

Page 696: GJavaDocs

Module 19: Java Messaging

696 Copyright © 2001, DevelopMentor Inc.

// 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

Page 697: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 697

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.

Page 698: GJavaDocs

Module 19: Java Messaging

698 Copyright © 2001, DevelopMentor Inc.

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

Page 699: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 699

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

Page 700: GJavaDocs

Module 19: Java Messaging

700 Copyright © 2001, DevelopMentor Inc.

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.

Page 701: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 701

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.

Page 702: GJavaDocs

Module 19: Java Messaging

702 Copyright © 2001, DevelopMentor Inc.

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

Page 703: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 703

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 ejb container

EJB object bean

context(run-time

environment)

systemservices

deploymentdescriptor

defines services to construct interposer

calls platform code

MessageListener

developer defined

container generated

ConnectionFactory

Connection

Session

MessageConsumer

Destinationsets

delivers

Sends/publishes

Figure 19.15: EJB interposition model for message-driven bean

Page 704: GJavaDocs

Module 19: Java Messaging

704 Copyright © 2001, DevelopMentor Inc.

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

Page 705: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 705

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 TellerMessageDrivenBeanimplements MessageDrivenBean, MessageListener {// No arg ejbCreate() like a stateless sessionpublic void ejbCreate() {...}// Method signatures mandated by MessageDrivenBean

interfacepublic void ejbRemove() {...}public void setMessageDrivenContext(MessageDrivenContext

ctx) {...}// Method signature mandated by MessageListener interfacepublic 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-

Page 706: GJavaDocs

Module 19: Java Messaging

706 Copyright © 2001, DevelopMentor Inc.

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.

Page 707: GJavaDocs

Module 19: Java Messaging

Copyright © 2001, DevelopMentor Inc. 707

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.

does not exist

container creates when needed:Class.newInstance()setMessageDrivenContext()ejbCreate()

message arrives at destination,onMessage()executes

onMessage()executionends

Executing onMessage() on behalf of some client sending a message

container destroys:ejbRemove()Object.finalize()

in pool (no identity)waiting to execute onMessage()

Figure 19.18: Lifecycle of a message-driven bean

Page 708: GJavaDocs

Module 19: Java Messaging

708 Copyright © 2001, DevelopMentor Inc.

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

Page 709: GJavaDocs

Copyright © 2001, DevelopMentor Inc. 709

Module 20

What's New

Page 710: GJavaDocs

710 Copyright © 2001, DevelopMentor Inc.

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

Page 711: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 711

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.

Page 712: GJavaDocs

Module 20: What's New

712 Copyright © 2001, DevelopMentor Inc.

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

Page 713: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 713

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.

Page 714: GJavaDocs

Module 20: What's New

714 Copyright © 2001, DevelopMentor Inc.

Listeners

Tag may be a listener

• Written the same way as standard event listeners

• Packaged as tags

• Add "listener" element to TLD

Page 715: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 715

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.

Page 716: GJavaDocs

Module 20: What's New

716 Copyright © 2001, DevelopMentor Inc.

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.

Page 717: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 717

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.

Page 718: GJavaDocs

Module 20: What's New

718 Copyright © 2001, DevelopMentor Inc.

Property Verification

Bean PropertyEditor can validate property

• Bean can have an associated PropertyEditor

• setAsText is then called

• Method can throw an IllegalArgumentException

Page 719: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 719

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.

Page 720: GJavaDocs
Page 721: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 721

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

Page 722: GJavaDocs

Module 20: What's New

722 Copyright © 2001, DevelopMentor Inc.

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

Page 723: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 723

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.

Page 724: GJavaDocs

Module 20: What's New

724 Copyright © 2001, DevelopMentor Inc.

Writing Listeners

Listeners Implement Appropriate Interface

• ServletContextListener

• ServletContextAttributeListener

• HttpSessionActivationListener

• HttpSessionAttributeListener

• Passed appropriate "Event" object

Page 725: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 725

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 WhitePagesServletListenerimplements

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.

Page 726: GJavaDocs

Module 20: What's New

726 Copyright © 2001, DevelopMentor Inc.

<listener><listener-class>

com.develop.ewebjava.lab.WhitePagesServletListener</listener-class>

</listener>

Figure 20.2: Configuring A Listener in the Deployment Descriptor

Page 727: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 727

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.

Page 728: GJavaDocs

Module 20: What's New

728 Copyright © 2001, DevelopMentor Inc.

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.

Page 729: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 729

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.

client

FilterFilterFilter

Servlet

Figure 20.3: Code Path to Servlet through filters

Page 730: GJavaDocs

Module 20: What's New

730 Copyright © 2001, DevelopMentor Inc.

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(...)

Page 731: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 731

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.

Page 732: GJavaDocs

Module 20: What's New

732 Copyright © 2001, DevelopMentor Inc.

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.

Page 733: GJavaDocs
Page 734: GJavaDocs

Module 20: What's New

734 Copyright © 2001, DevelopMentor Inc.

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

Page 735: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 735

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 extendsHttpServletRequestWrapper{

SessionRequestWrapper(HttpServletRequest request){

super(request);}// Other code here

}

Figure 20.6: Creating a Request Wrapper

Page 736: GJavaDocs

Module 20: What's New

736 Copyright © 2001, DevelopMentor Inc.

Filter Configuration

Filter Configures in Deployment Descriptor

• May be associated with a URL

• May be associated with a named resource

Page 737: GJavaDocs

Module 20: What's New

Copyright © 2001, DevelopMentor Inc. 737

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

Page 738: GJavaDocs

Module 20: What's New

738 Copyright © 2001, DevelopMentor Inc.

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

Page 739: GJavaDocs

Glossary

Copyright © 2001, DevelopMentor Inc. 739

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

Page 740: GJavaDocs

Glossary

740 Copyright © 2001, DevelopMentor Inc.

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.

Page 741: GJavaDocs

Bibliography

Copyright © 2001, DevelopMentor Inc. 741

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

Page 742: GJavaDocs

Bibliography

742 Copyright © 2001, DevelopMentor Inc.

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.

Page 743: GJavaDocs

Bibliography

Copyright © 2001, DevelopMentor Inc. 743

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.