Pro Hibernate and MongoDB - Home - Springer978-1-4302-5795-0/1.pdf · Pro Hibernate and MongoDB ......

21
Pro Hibernate and MongoDB Anghel Leonard

Transcript of Pro Hibernate and MongoDB - Home - Springer978-1-4302-5795-0/1.pdf · Pro Hibernate and MongoDB ......

Pro Hibernate and MongoDB

Anghel Leonard

Pro Hibernate and MongoDB

Copyright © 2013 by Anghel Leonard

This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now known or hereafter developed. Exempted from this legal reservation are brief excerpts in connection with reviews or scholarly analysis or material supplied specifically for the purpose of being entered and executed on a computer system, for exclusive use by the purchaser of the work. Duplication of this publication or parts thereof is permitted only under the provisions of the Copyright Law of the Publisher’s location, in its current version, and permission for use must always be obtained from Springer. Permissions for use may be obtained through RightsLink at the Copyright Clearance Center. Violations are liable to prosecution under the respective Copyright Law.

ISBN-13 (pbk): 978-1-4302-5794-3

ISBN-13 (electronic): 978-1-4302-5795-0

Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark.

The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to proprietary rights.

While the advice and information in this book are believed to be true and accurate at the date of publication, neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or omissions that may be made. The publisher makes no warranty, express or implied, with respect to the material contained herein.

President and Publisher: Paul ManningLead Editor: Steve AnglinTechnical Reviewer: Manuel JordanEditorial Board: Steve Anglin, Ewan Buckingham, Gary Cornell, Louise Corrigan, Morgan Ertel,

Jonathan Gennick, Jonathan Hassell, Robert Hutchinson, Michelle Lowman, James Markham, Matthew Moodie, Jeff Olson, Jeffrey Pepper, Douglas Pundick, Ben Renow-Clarke, Dominic Shakeshaft, Gwenan Spearing, Matt Wade, Tom Welsh

Coordinating Editor: Kevin SheaCopy Editor: Sharon TerdemanCompositor: SPi GlobalIndexer: SPi GlobalArtist: SPi GlobalCover Designer: Anna Ishchenko

Distributed to the book trade worldwide by Springer Science+Business Media New York, 233 Spring Street, 6th Floor, New York, NY 10013. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail [email protected], or visit www.springeronline.com.

For information on translations, please e-mail [email protected], or visit www.apress.com.

Apress and friends of ED books may be purchased in bulk for academic, corporate, or promotional use. eBook versions and licenses are also available for most titles. For more information, reference our Special Bulk Sales–eBook Licensing web page at www.apress.com/bulk-sales.

Any source code or other supplementary materials referenced by the author in this text is available to readers at www.apress.com. For detailed information about how to locate your book’s source code, go to www.apress.com/source-code/.

This book is dedicated to Rafael Nadal.Of course, it is also dedicated to my parents and my wife.

Love you all, each and every one.

—Anghel Leonard

v

Contents at a Glance

About the Author ���������������������������������������������������������������������������������������������������������������xiii

About the Technical Reviewer �������������������������������������������������������������������������������������������� xv

Acknowledgments ������������������������������������������������������������������������������������������������������������ xvii

Introduction ����������������������������������������������������������������������������������������������������������������������� xix

Chapter 1: Getting Started with Hibernate OGM ■ ����������������������������������������������������������������1

Chapter 2: Hibernate OGM and MongoDB ■ ������������������������������������������������������������������������23

Chapter 3: Bootstrapping Hibernate OGM ■ ������������������������������������������������������������������������37

Chapter 4: Hibernate OGM at Work ■ ����������������������������������������������������������������������������������51

Chapter 5: Hibernate OGM and JPA 2�0 Annotations ■ �����������������������������������������������������121

Chapter 6: Hibernate OGM Querying MongoDB ■ ��������������������������������������������������������������205

Chapter 7: MongoDB e-Commerce Database Model ■ ������������������������������������������������������241

Chapter 8: MongoDB e-Commerce Database Querying ■ �������������������������������������������������269

Chapter 9: Migrate MongoDB Database to Cloud ■ ����������������������������������������������������������283

Chapter 10: Migrating RafaEShop Application on OpenShift ■ �����������������������������������������297

Index ���������������������������������������������������������������������������������������������������������������������������������355

vii

Contents

About the Author ���������������������������������������������������������������������������������������������������������������xiii

About the Technical Reviewer �������������������������������������������������������������������������������������������� xv

Acknowledgments ������������������������������������������������������������������������������������������������������������ xvii

Introduction ����������������������������������������������������������������������������������������������������������������������� xix

Chapter 1: Getting Started with Hibernate OGM ■ ����������������������������������������������������������������1

Features and Expectations ������������������������������������������������������������������������������������������������������������2

Hibernate OGM Architecture ����������������������������������������������������������������������������������������������������������2

Persisting Data ������������������������������������������������������������������������������������������������������������������������������������������������������ 4

Querying Data �������������������������������������������������������������������������������������������������������������������������������������������������������� 8

Get the Hibernate OGM Distribution ����������������������������������������������������������������������������������������������9

Getting Hibernate OGM from the Maven Central Repository ������������������������������������������������������������������������������� 10

Getting Hibernate OGM from the Maven Command Line ������������������������������������������������������������������������������������� 11

Adding MongoDB Artifacts ����������������������������������������������������������������������������������������������������������������������������������� 14

Getting a Hibernate OGM Distribution Using the NetBeans IDE ��������������������������������������������������������������������������� 16

Getting the Hibernate OGM Distribution Using the Eclipse IDE ���������������������������������������������������������������������������� 19

Obtain the MongoDB Distribution ������������������������������������������������������������������������������������������������21

Summary �������������������������������������������������������������������������������������������������������������������������������������22

Chapter 2: Hibernate OGM and MongoDB ■ ������������������������������������������������������������������������23

Configuring MongoDB-Hibernate OGM Properties ����������������������������������������������������������������������23

Data Storing Representation �������������������������������������������������������������������������������������������������������25

Storing Entities ���������������������������������������������������������������������������������������������������������������������������������������������������� 26

Storing Primary Keys ������������������������������������������������������������������������������������������������������������������������������������������� 28

Storing Associations �������������������������������������������������������������������������������������������������������������������������������������������� 29

■ Contents

viii

Managing Transactions ���������������������������������������������������������������������������������������������������������������35

Managing Queries �����������������������������������������������������������������������������������������������������������������������35

Summary �������������������������������������������������������������������������������������������������������������������������������������35

Chapter 3: Bootstrapping Hibernate OGM ■ ������������������������������������������������������������������������37

Brief Overview of JPA ������������������������������������������������������������������������������������������������������������������37

Brief Overview of JTA ������������������������������������������������������������������������������������������������������������������39

MongoDB and Transactions ���������������������������������������������������������������������������������������������������������40

Brief Overview of Hibernate Native API ���������������������������������������������������������������������������������������40

Bootstrapping Hibernate OGM Using JPA ������������������������������������������������������������������������������������41

Bootstrap Hibernate OGM Using Hibernate Native API ����������������������������������������������������������������44

Hibernate OGM Obsolete Configuration Options ��������������������������������������������������������������������������50

Summary �������������������������������������������������������������������������������������������������������������������������������������50

Chapter 4: Hibernate OGM at Work ■ ����������������������������������������������������������������������������������51

General Prerequisites ������������������������������������������������������������������������������������������������������������������51

Java SE and MongoDB—the Hello World Example ���������������������������������������������������������������������52

Prerequisites�������������������������������������������������������������������������������������������������������������������������������������������������������� 52

Developing ����������������������������������������������������������������������������������������������������������������������������������������������������������� 53

Testing ����������������������������������������������������������������������������������������������������������������������������������������������������������������� 55

Hibernate OGM via Hibernate Native API �������������������������������������������������������������������������������������55

Hibernate OGM in a Non-JTA Environment (JDBC Transactions, Apache Tomcat 7) �������������������������������������������� 55

Hibernate OGM in a Standalone JTA Environment (JBoss JTA, Apache Tomcat 7) ���������������������������������������������� 63

Hibernate OGM in a Built-in JTA Environment (no EJB, GlassFish AS 3) �������������������������������������������������������������� 71

Hibernate OGM in a Built-in JTA Environment (EJB 3/BMT, GlassFish AS 3)�������������������������������������������������������� 76

Hibernate OGM in a Built-in JTA Environment (EJB 3/CMT, GlassFish AS 3) �������������������������������������������������������� 80

Hibernate OGM via the Java Persistence API (JPA 2�0) ���������������������������������������������������������������83

Hibernate OGM in a Built-in JTA Environment (EJB 3, GlassFish AS 3)���������������������������������������������������������������� 83

Hibernate OGM in a Built-in JTA Environment (EJB 3, JBoss AS 7) ��������������������������������������������������������������������� 88

Hibernate OGM in a Standalone JTA environment (Apache Tomcat 7) ���������������������������������������������������������������� 94

■ Contents

ix

Hibernate OGM in a Built-in JTA Environment (JBoss AS 7 and Seam 3 Application) ����������������������������������������� 99

Hibernate OGM in a Built-in JTA Environment (GlassFish 3 and Spring 3 Application) �������������������������������������� 107

Hibernate OGM in a non-JTA Environment (RESOURCE_LOCAL, Apache Tomcat 7) ������������������������������������������ 113

Synthesis �����������������������������������������������������������������������������������������������������������������������������������118

Hibernate OGM via JPA in an EE Container �������������������������������������������������������������������������������������������������������� 118

Hibernate OGM via Hibernate Native API in an EE Container ����������������������������������������������������������������������������� 118

Hibernate OGM via JPA in Standalone JTA �������������������������������������������������������������������������������������������������������� 119

Hibernate OGM via Hibernate Native API in Standalone JTA������������������������������������������������������������������������������ 119

Hibernate OGM via JPA in Non-JTA ������������������������������������������������������������������������������������������������������������������� 119

Hibernate OGM via Hibernate Native API in Non-JTA ����������������������������������������������������������������������������������������� 119

Summary �����������������������������������������������������������������������������������������������������������������������������������120

Chapter 5: Hibernate OGM and JPA 2�0 Annotations ■ �����������������������������������������������������121

Java Supported Types ���������������������������������������������������������������������������������������������������������������121

Eager and Lazy Loading Considerations �����������������������������������������������������������������������������������122

Cascadable Operations Considerations �������������������������������������������������������������������������������������122

Entity Mapping ��������������������������������������������������������������������������������������������������������������������������123

@Entity Annotation �������������������������������������������������������������������������������������������������������������������������������������������� 123

@Id Annotation �������������������������������������������������������������������������������������������������������������������������������������������������� 124

@EmbeddedId Annotation ��������������������������������������������������������������������������������������������������������������������������������� 133

@IdClass Annotation ������������������������������������������������������������������������������������������������������������������������������������������ 135

@Table Annotation ��������������������������������������������������������������������������������������������������������������������������������������������� 137

@Column Annotation ����������������������������������������������������������������������������������������������������������������������������������������� 138

@Temporal Annotation �������������������������������������������������������������������������������������������������������������������������������������� 140

@Transient Annotation��������������������������������������������������������������������������������������������������������������������������������������� 142

@Embedded and @Embeddable Annotations ��������������������������������������������������������������������������������������������������� 143

@Enumerated Annotation ���������������������������������������������������������������������������������������������������������������������������������� 146

@Cacheable Annotation������������������������������������������������������������������������������������������������������������������������������������� 148

@MappedSuperclass Annotation ����������������������������������������������������������������������������������������������������������������������� 155

@ElementCollection Annotation ������������������������������������������������������������������������������������������������������������������������ 158

JPA Lifecycle Events @EntityListeners, @ExcludeDefaultListeners, @ExcludeSuperclassListeners Annotations ������������������������������������������������������������������������������������������������������� 163

■ Contents

x

@Version Annotation ����������������������������������������������������������������������������������������������������������������������������������������� 171

@Access Annotation ������������������������������������������������������������������������������������������������������������������������������������������ 176

Associations ������������������������������������������������������������������������������������������������������������������������������������������������������ 179

Direction in Entity Associations ������������������������������������������������������������������������������������������������������������������������� 179

Unsupported JPA 2�0 Annotations ���������������������������������������������������������������������������������������������202

Summary �����������������������������������������������������������������������������������������������������������������������������������203

Chapter 6: Hibernate OGM Querying MongoDB ■ ��������������������������������������������������������������205

MongoDB Native Query �������������������������������������������������������������������������������������������������������������206

Hibernate OGM and CRUD Operations ���������������������������������������������������������������������������������������211

Hibernate Search and Apache Lucene ��������������������������������������������������������������������������������������214

Common Steps �������������������������������������������������������������������������������������������������������������������������������������������������� 217

Hibernate Search/Apache Lucene Querying—OGM via Native API ������������������������������������������������������������������� 222

Hibernate Search/Apache Lucene Querying—OGM via JPA ������������������������������������������������������������������������������ 231

Hibernate OGM JP-QL Parser ����������������������������������������������������������������������������������������������������239

Summary �����������������������������������������������������������������������������������������������������������������������������������240

Chapter 7: MongoDB e-Commerce Database Model ■ ������������������������������������������������������241

MongoDB E-commerce Database Architecture �������������������������������������������������������������������������242

Model the Categories Collection (categories_c) ������������������������������������������������������������������������243

Model The Products Collection (products_c) �����������������������������������������������������������������������������245

Model the Customers Collection (customers_c) ������������������������������������������������������������������������250

Model The Orders Collection (orders_c) ������������������������������������������������������������������������������������256

Model The Inventory Collection (inventory_c) ���������������������������������������������������������������������������263

Summary �����������������������������������������������������������������������������������������������������������������������������������267

Chapter 8: MongoDB e-Commerce Database Querying ■ �������������������������������������������������269

Display the Categories of Products �������������������������������������������������������������������������������������������271

Display the Promotional Products ���������������������������������������������������������������������������������������������273

Display the Products From a Category ��������������������������������������������������������������������������������������274

Search for a Product by Name ��������������������������������������������������������������������������������������������������276

■ Contents

xi

Find a Customer By E-mail And Password ��������������������������������������������������������������������������������277

Place an Order ���������������������������������������������������������������������������������������������������������������������������278

Check the Inventory ������������������������������������������������������������������������������������������������������������������279

Restore the Inventory ����������������������������������������������������������������������������������������������������������������280

Considerations for Developing the Admin GUI ���������������������������������������������������������������������������281

Summary �����������������������������������������������������������������������������������������������������������������������������������282

Chapter 9: Migrate MongoDB Database to Cloud ■ ����������������������������������������������������������283

Migrating the MongoDB Database to the MongoHQ Cloud ��������������������������������������������������������283

Migrating the MongoDB Database to the MongoLab Cloud �������������������������������������������������������289

Connecting to the MongoHQ or MongoLab Cloud Database ������������������������������������������������������294

Summary �����������������������������������������������������������������������������������������������������������������������������������296

Chapter 10: Migrating RafaEShop Application on OpenShift ■ �����������������������������������������297

Creating a Free Account on OpenShift ��������������������������������������������������������������������������������������297

Installing the OpenShift RHC Client Tools on Windows ��������������������������������������������������������������301

Installing Ruby ��������������������������������������������������������������������������������������������������������������������������������������������������� 301

Installing Git ������������������������������������������������������������������������������������������������������������������������������������������������������� 302

Testing Ruby and Git from the Shell ������������������������������������������������������������������������������������������������������������������ 303

Installing the OpenShift Gem ����������������������������������������������������������������������������������������������������������������������������� 305

Fixing a Known Issue ����������������������������������������������������������������������������������������������������������������308

Migrating the RafaEShop Application to OpenShift with JBoss AS 7 ����������������������������������������308

Monitoring the JBoss AS 7 Log �������������������������������������������������������������������������������������������������������������������������� 317

Commit Changes ����������������������������������������������������������������������������������������������������������������������������������������������� 319

Migrating the RafaEShop Application as a WAR ������������������������������������������������������������������������������������������������ 321

Migrating the RafaEShop Application as a Maven Project ��������������������������������������������������������������������������������� 322

Migrating the RafaEShop Application to OpenShift with GlassFish 3 AS �����������������������������������327

Monitoring GlassFish Start/Stop ������������������������������������������������������������������������������������������������������������������������ 348

Commit Changes ����������������������������������������������������������������������������������������������������������������������������������������������� 349

Fixing Known Issues ������������������������������������������������������������������������������������������������������������������������������������������ 349

Monitoring the GlassFish Log ���������������������������������������������������������������������������������������������������������������������������� 350

■ Contents

xii

Test It!����������������������������������������������������������������������������������������������������������������������������������������351

Cautions ������������������������������������������������������������������������������������������������������������������������������������������������������������� 352

Good To Know ����������������������������������������������������������������������������������������������������������������������������354

Disclaimer ���������������������������������������������������������������������������������������������������������������������������������354

Summary �����������������������������������������������������������������������������������������������������������������������������������354

Index ���������������������������������������������������������������������������������������������������������������������������������355

xiii

About the Author

Anghel Leonard is a senior Java developer with more than 12 years of experience in Java SE, Java EE, and related frameworks. He has written and published more than 50 articles about Java technologies and more than 500 tips and tricks for JavaBoutique, O’Reilly, DevX, Developer and InformIT. In addition, he wrote two books about XML and Java (one for beginners and one for advanced developers) for Albastra, a Romanian publisher; three books for Packt: JBoss Tools 3 Developer Guide, JSF 2.0 Cookbook, and JSF 2.0 Cookbook LITE; and two books for Apress: Pro Java 7 NIO 2, and Pro Hibernate and MongoDB. Currently, he’s developing web applications using the latest Java technologies (EJB 3.0, CDI, Spring, JSF, Struts, Hibernate, and so on). For the past two years, he has focused on developing rich Internet applications for geographic information systems.

xv

About the Technical Reviewer

Manuel Jordan Elera is an autodidactic developer and researcher who enjoys learning new technologies for his own experiments and for creating new integrations.

Manuel won the 2010 Springy Award—Community Champion. In his little free time, he reads the Bible and composes music on his guitar. Manuel is a senior member, known as dr_pompeii, of the Spring Community Forums.

Manuel has served as a technical reviewer for the following books (all published by Apress):

• ProSpringSourcedmServer(2009)

• SpringEnterpriseRecipes(2009)

• SpringRecipes(SecondEdition)(2010)

• ProSpringIntegration(2011)

• ProSpringBatch(2011)

• ProSpring3(2012)

• ProSpringMVC:WithWebFlow(2012)

• ProSpringSecurity(2013)

You can read his blog and contact him at http://manueljordan.wordpress.com/. You can also follow his Twitter account, @dr_pompeii.

xvii

Acknowledgments

Thank you, God, because without you nothing is possible. Thank you to the Apress team for trusting in me to write this book and for the hard work you put into this project. Special thanks to Steve Anglin, Manuel Jordan, Kevin Shea, Sharon Terdeman, and Tom Welsh.

—Anghel Leonard

xix

Introduction

This book covers all the important aspects of developing Hibernate OGM-MongoDB applications. It provides clear instructions for getting the most out of the Hibernate OGM-MongoDB duo and offers many examples of integrating Hibernate OGM by means of both the Hibernate Native API and the Java Persistence API. You will learn how to develop desktop, web, and enterprise applications for the most popular web and enterprise servers, such as Tomcat, JBoss AS, and Glassfish AS. You’ll see how to take advantage of Hibernate OGM-MongoDB together with many common technologies, such as JSF, Spring, Seam, EJB, and more. Finally, you’ll learn how to migrate to the cloud—MongoHQ, MongoLab, and OpenShift.

Who This Book Is ForThis book is for experienced Java developers who are interested in exploring Hibernate solutions for NoSQL databases. For the opening chapters (Chapters 1–3), it’s enough to be familiar with the main aspects of the ORM paradigm, the Hibernate Native API, and JPA. The book provides brief overviews of these concepts. Starting with Chapter 4, you should have some knowledge about developing web applications (using NetBeans or Eclipse) deployed under the Tomcat, JBoss AS, or GlassFish AS servers. Moreover, you need to be familiar with the Java technologies and frameworks that are commonly used in web applications, such as servlets, EJB, JSF, JSP, Seam, Spring, and so on.

How This Book Is StructuredHere’s the main focus of each chapter:

Chapter 1: Getting Started with Hibernate OGMThis chapter provides a brief introduction to the Hibernate OGM world. In the first part of the chapter, I discuss the Hibernate OGM architecture, its current features, and what we can expect in terms of future support. I then offer several alternatives for downloading, installing, and configuring Hibernate OGM and MongoDB.

Chapter 2: Hibernate OGM and MongoDBIn this chapter, I define more clearly the relationship between Hibernate OGM and MongoDB by focusing on how Hibernate OGM works with MongoDB. You learn how data is stored, how primary keys and associations are mapped, and how to deal with transactions and queries.

Chapter 3: Bootstrapping Hibernate OGMThis chapter shows how Hibernate OGM can be bootstrapped by means of the Hibernate Native API and JPA.

■ IntroduCtIon

xx

Chapter 4: Hibernate OGM at WorkThis is one of the most important chapters. You learn how to integrate Hibernate OGM and MongoDB in the most common web and enterprise Java applications deployed on different servers. Here is the entire list of applications:

• JavaSEandMongoDB—a“Helloworld”example

• HibernateOGM(viaHibernateNativeAPI)inanon-JTAenvironment(JDBCTransactions,Tomcat 7)

• HibernateOGM(viaHibernateNativeAPI)inastandaloneJTAenvironment(JBossJTA,Tomcat 7)

• HibernateOGM(viaHibernateNativeAPI)inabuilt-inJTAenvironment(noEJB,GlassFish3)

• HibernateOGM(viaHibernateNativeAPI)inabuilt-inJTAenvironment(EJB/BMT,GlassFish3)

• HibernateOGM(viaHibernateNativeAPI)inabuilt-inJTAenvironment(EJB/CMT,GlassFish3)

• HibernateOGM(viaJPA)inabuilt-inJTAenvironment(GlassFishAS3)

• HibernateOGM(viaJPA)inabuilt-inJTAenvironment(JBossAS7)

• HibernateOGM(viaJPA)inabuilt-inJTAenvironment(JBossAS7andSeamapplication)

• HibernateOGM(viaJPA)inabuilt-inJTAenvironment(GlassFishandSpringapplication)

• HibernateOGM(viaJPA)JPA/JTAinastandaloneJTAenvironment(Tomcat)

• HibernateOGMinanon-JTAenvironment(RESOURCE_LOCAL,ApacheTomcat7)

Chapter 5: Hibernate OGM and JPA 2.0 AnnotationsMapping Java entities in Hibernate OGM can be divided into supported and non-supported annotations. In this chapter, I show the supported annotations, as well as how much of each annotation is supported.

Chapter 6: Hibernate OGM Querying MongoDBThis chapter explores the querying capabilities of Hibernate OGM. I start with a MongoDB native query and progress to complex queries written with Hibernate Search and Apache Lucene.

Chapter 7: MongoDB e-Commerce Database ModelAt this point in the book, you will have acquired sufficent expertise to develop a real application that involves Hibernate OGM and MongoDB. An e-commerce web site is a good start and an interesting study case, so in this chapter I adapt a classic SQL database model to the Hibernate OGM and MongoDB style. I also examine aspects of e-commerce database architecture.

Chapter 8: MongoDB e-Commerce Database QueryingAfter you develop a MongoDB e-commerce database model, it’s time to sketch and implement the main e-commerce-specific queries. In this chapter, I use Hibernate Search and Apache Lucene to write such queries. The result is a complete e-commerce application named RafaEShop.

■ IntroduCtIon

xxi

Chapter 9: Migrate MongoDB Database to CloudIn this chapter, you learn how to migrate the MongoDB e-commerce database developed in Chapter 7 into two clouds: MongoHQ and MongoLab.

Chapter 10: Migrating RafaEShop Application on OpenShiftThis final chapter is a detailed guide for migrating the e-commerce RafaEShop application to the OpenShift cloud on two enterprise servers: JBoss AS and GlassFish AS.

Downloading the CodeThe code for the examples shown in this book is available on the Apress web site, www.apress.com. You’ll find the link onthebook’sinformationpageundertheSourceCode/Downloadstab.ThistabislocatedunderneaththeRelatedTitles section of the page.

Contacting the AuthorShould you have any questions or comments—or even spot a mistake you think I should know about—you can contact me at [email protected].