DELIVERY & GIFT DETAILS:
Usually ships within 24 hours
Delivery Time and Shipping Rates
Eligible for gift wrap & gift message.
Textbook (Paperback - New Edition)
Textbook Information
This guide to J2EE focuses on solving common problems and avoiding debilitating mistakes. Johnson (a Java architect) examines the complexities of J2EE services and advocates the simplest possible solutions. Specific instructions are offered for using distributed architecture, EJB, data access strategies, web interface design, and J2EE applications design. Annotation © 2004 Book News, Inc., Portland, OR
More Reviews and RecommendationsRod Johnson is an enterprise Java architect specializing in scalable web applications. He has worked with both Java and J2EE since their release, and he is a member of JSR 154 Expert Group defining the Servlet 2.4 specification.
What is this book about?
The results of using J2EE in practice are often disappointing: applications are often slow, unduly complex, and take too long to develop. Rod Johnson believes that the problem lies not in J2EE itself, but in that it is often used badly. Many J2EE publications advocate approaches that, while fine in theory, often fail in reality, or deliver no real business value.
Expert One-on-One: J2EE Design and Development aims to demystify J2EE development. Using a practical focus, it shows how to use J2EE technologies to reduce, rather than increase, complexity. Rod draws on his experience of designing successful high-volume J2EE applications and salvaging failing projects, as well as intimate knowledge of the J2EE specifications, to offer a real-world, how-to guide on how you too can make J2EE work in practice.
It will help you to solve common problems with J2EE and avoid the expensive mistakes often made in J2EE projects. It will guide you through the complexity of the J2EE services and APIs to enable you to build the simplest possible solution, on time and on budget. Rod takes a practical, pragmatic approach, questioning J2EE orthodoxy where it has failed to deliver results in practice and instead suggesting effective, proven approaches.
What does this book cover?
In this book, you will learn
Who is this book for?
This book would be of value to mostenterprise developers. Although some of the discussion (for example, on performance and scalability) would be most relevant to architects and lead developers, the practical focus would make it useful to anyone with some familiarity with J2EE. Because of the complete design-deployment coverage, a less advanced developer could work through the book along with a more introductory text, and successfully build and understand the sample application. This comprehensive coverage would also be useful to developers in smaller organisations, who might be called upon to fill several normally distinct roles.
What is special about this book?
Wondering what differentiates this book from others like it in the market? Take a look:
| Introduction | 1 | |
| J2EE Myths | 2 | |
| How is this Book Different? | 5 | |
| My Approach | 6 | |
| Who this Book is for | 7 | |
| Aims of this Book | 7 | |
| What this Book Covers | 7 | |
| Assumed Knowledge | 8 | |
| Recommended Reading | 9 | |
| What You Need to Use this Book | 9 | |
| Chapter 1 | J2EE Architectures | 15 |
| Goals of an Enterprise Architecture | 16 | |
| Deciding Whether to Use a Distributed Architecture | 18 | |
| New Considerations in J2EE Design | 19 | |
| When to Use EJB | 20 | |
| Implications ofUsing EJB | 20 | |
| Questionable Arguments for Using EJB | 22 | |
| Compelling Arguments for Using EJB | 22 | |
| Arguments for Using EJB to Consider on a Case-by-Case Basis | 23 | |
| Accessing Data | 24 | |
| J2EE Data Access Shibboleths | 24 | |
| State Management | 26 | |
| J2EE Architectures | 26 | |
| Common Concepts | 27 | |
| Non-distributed Architectures | 28 | |
| Distributed Architectures | 32 | |
| Web Tier Design | 36 | |
| The Model View Controller (MVC) Architectural Pattern | 36 | |
| Connectivity Between the Web Tier and Business Objects | 38 | |
| Designing Applications for Portability | 38 | |
| Summary | 40 | |
| Chapter 2 | J2EE Projects: Choices and Risks | 43 |
| Developing a Policy on Specification Versions | 44 | |
| Choosing an Application Server | 45 | |
| When to Choose an Application Server | 46 | |
| Defining the Requirements | 47 | |
| Evaluation Criteria | 48 | |
| Choice Process | 54 | |
| Top Mistakes in Choosing an Application Server | 54 | |
| The "Neat Technology" Trap | 55 | |
| When to Use Alternative Technologies to Supplement J2EE | 56 | |
| Portability Issues | 56 | |
| What does Portability Mean? | 57 | |
| A Pragmatic Approach to Portability | 58 | |
| Staging Environments and Release Management | 58 | |
| Building a Team | 60 | |
| Team Structure | 60 | |
| Choosing Development Tools | 63 | |
| Visual Modeling Tools | 64 | |
| IDEs | 64 | |
| Build Utilities | 64 | |
| Code Generators | 66 | |
| Version Control | 67 | |
| Identifying and Mitigating Risks | 67 | |
| Summary | 71 | |
| Chapter 3 | Testing J2EE Applications | 73 |
| What Can Testing Achieve? | 74 | |
| Definitions | 75 | |
| Testing Correctness | 76 | |
| The XP Approach to Testing | 76 | |
| Writing Test Cases | 78 | |
| Unit Testing | 78 | |
| Should Testing Strategy Affect How We Write Code? | 90 | |
| Integration and Acceptance Testing | 92 | |
| Testing Business Objects | 92 | |
| Testing Web Interfaces | 100 | |
| Design Implications | 105 | |
| Testing Performance and Scalability | 105 | |
| Load Testing EJBs and Other Business Objects | 106 | |
| Load Testing Web Interfaces | 107 | |
| Automating Tests | 107 | |
| Complementary Approaches to Testing | 108 | |
| Summary | 110 | |
| Chapter 4 | Design Techniques and Coding Standards for J2EE Projects | 113 |
| 00 Design Recommendations for J2EE Applications | 114 | |
| Achieving Loose Coupling with Interfaces | 115 | |
| Prefer Object Composition to Concrete Inheritance | 115 | |
| The Template Method Design Pattern | 117 | |
| The Strategy Design Pattern | 119 | |
| Using Callbacks to Achieve Extensibility | 120 | |
| The Observer Design Pattern | 122 | |
| Consider Consolidating Method Parameters | 124 | |
| Exception Handling--Checked or Unchecked Exceptions | 125 | |
| Using Reflection | 132 | |
| Using JavaBeans to Achieve Flexibility | 138 | |
| Avoid a Proliferation of Singletons by Using an Application Registry | 139 | |
| Refactoring | 142 | |
| Coding Standards | 142 | |
| Start from the Standard | 143 | |
| Allocation of Responsibilities | 145 | |
| Avoid Code Duplication | 146 | |
| Avoid Literal Constants | 147 | |
| Visibility and Scoping | 149 | |
| Using the final Keyword | 153 | |
| Implementing toString() Methods Useful for Diagnostics | 155 | |
| Defensive Coding Practices | 156 | |
| Prefer Arrays to Collections in Public Method Signatures | 157 | |
| Documenting Code | 158 | |
| Logging | 160 | |
| Why (and How) Not to Reinvent the Wheel | 166 | |
| Help! API Overload | 167 | |
| Using Frameworks | 167 | |
| Summary | 171 | |
| Chapter 5 | Requirements for the Sample Application | 179 |
| Overview | 180 | |
| User Populations | 180 | |
| Public Internet Users | 180 | |
| Box Office Users | 181 | |
| Administrators | 182 | |
| Assumptions | 182 | |
| Scope Limitations | 183 | |
| Delivery Schedule | 183 | |
| Internet User Interface | 183 | |
| Basic Workflow | 184 | |
| Error Handling | 185 | |
| Application Screens | 185 | |
| Box Office User Interface | 198 | |
| Non-Functional Requirements | 198 | |
| Hardware and Software Environment | 199 | |
| Summary | 200 | |
| Chapter 6 | Applying J2EE Technologies | 203 |
| When is a Distributed Architecture Appropriate? | 204 | |
| Distributed Applications and Scalability | 205 | |
| Distributed Applications and Reliability | 206 | |
| Scalable and Robust Architectures | 207 | |
| High-level Architecture for the Sample Application | 209 | |
| Deciding When to Use EJB | 209 | |
| Using EJB to Implement a Distributed Architecture | 209 | |
| Transaction Management | 210 | |
| EJB and Authorization | 213 | |
| EJB and Multi-threading | 214 | |
| Declarative Configuration Management | 214 | |
| The Downside of EJB | 214 | |
| EJBs in the Sample Application | 222 | |
| Deciding How to Use EJB | 223 | |
| What Should EJBs Do? | 223 | |
| When to Use Local or Remote Interfaces | 223 | |
| Using EJBs in the Sample Application | 227 | |
| Deciding when to use Asynchronous Calling with JMS | 228 | |
| Message-Oriented Middleware (MOM) and JMS | 228 | |
| Producing Messages | 228 | |
| Consuming Messages | 229 | |
| When to Use Asynchronous Calling | 232 | |
| JMS in the Sample Application | 234 | |
| Authentication and Authorization | 235 | |
| The Standard Security Infrastructure | 235 | |
| The Server Implementation | 237 | |
| Deciding When to Use XML | 238 | |
| Using XSLT in J2EE Applications | 238 | |
| "Deep" Use of XML | 239 | |
| Converting Between JavaBeans and XML | 241 | |
| J2EE and XML in the Future | 244 | |
| XML in the Sample Application | 245 | |
| Caching to Improve Performance | 245 | |
| Caching Options | 245 | |
| A Caching Strategy for the Sample Application | 247 | |
| Summary | 248 | |
| Chapter 7 | Data Access in J2EE Applications | 251 |
| Data Access Goals | 252 | |
| Business Logic and Persistence Logic | 252 | |
| Object-Driven and Database-Driven Modeling: A Philosophical Debate | 253 | |
| O/R Mapping and the "Impedance Mismatch" | 255 | |
| The Data Access Object (DAO) Pattern | 257 | |
| Working with Relational Databases | 259 | |
| Referential Integrity | 259 | |
| Stored Procedures, Triggers, and Views | 259 | |
| RDBMS Performance Issues | 262 | |
| Portability Versus Performance | 263 | |
| Exchanging Data in Distributed Applications | 265 | |
| The Value Object J2EE Pattern | 265 | |
| "Generic" Value Objects | 267 | |
| "Disconnected" Data Access Using JDBC Rowsets | 267 | |
| Common Data Access Issues | 268 | |
| Transaction Isolation | 268 | |
| Pessimistic and Optimistic Locking | 269 | |
| Primary Key Generation Strategies | 269 | |
| Where to Perform Data Access | 273 | |
| Data Access in the EJB Tier | 273 | |
| Data Access in the Middle Tier without Using EJB | 275 | |
| Data Access in the Web Tier | 276 | |
| Summary | 278 | |
| Data Modeling in the Sample Application | 278 | |
| Chapter 8 | Data Access Using Entity Beans | 285 |
| Entity Bean Concepts | 286 | |
| Definition | 287 | |
| How Should We Use Entity Beans? | 288 | |
| CMP Versus BMP | 292 | |
| Entity Beans in EJB 2.0 | 294 | |
| Local Interfaces | 294 | |
| Home Interface Business Methods | 295 | |
| EJB 2.0 CMP | 296 | |
| Entity Bean Caching | 300 | |
| Entity Bean Locking Strategies | 301 | |
| Read-only and "Read-mostly" Entities | 302 | |
| Transactional Entity Caching | 304 | |
| Entity Bean Performance | 305 | |
| Tool Support for Entity Beans | 306 | |
| Summary | 306 | |
| Chapter 9 | Practical Data Access | 311 |
| Data Access Technology Choices | 312 | |
| SQL-Based Technologies | 312 | |
| O/R Mapping Technologies | 315 | |
| Choosing a Data Access Strategy for the Sample Application | 319 | |
| JDBC Subtleties | 320 | |
| Correct Exception Handling | 320 | |
| Extracting Information from SQLExceptions | 322 | |
| The PreparedStatement Question | 323 | |
| A Generic JDBC Abstraction Framework | 324 | |
| Motivation | 325 | |
| Aims | 326 | |
| Exception Handling | 327 | |
| Two Levels of Abstraction | 333 | |
| A Framework to Control JDBC Workflow and Error Handling | 333 | |
| A Higher Level of Abstraction: Modeling RDBMS Operations as Java Objects | 342 | |
| JDBC Abstraction Summary | 351 | |
| Implementing the DAO Pattern In the Sample Application | 353 | |
| Summary | 360 | |
| Chapter 10 | Session Beans | 363 |
| Using Stateless Session Beans | 364 | |
| Benefits of Stateless Session Beans | 364 | |
| Stateless Session Beans and Internal State | 365 | |
| Implications of Stateless Session Bean Pooling | 365 | |
| Using Stateful Session Beans | 366 | |
| Why Not to Use Stateful Session Beans | 366 | |
| When to Use Stateful Session Beans | 370 | |
| Session Synchronization | 370 | |
| Protecting Stateful Session Beans from Concurrent Calls | 371 | |
| Patterns for Achieving Stateful Functionality with SLSBs | 371 | |
| Using a Stateful Session Bean as Controller | 373 | |
| J2EE Design Patterns Applicable to Session Beans | 373 | |
| The Session Facade Pattern in Distributed J2EE Applications | 374 | |
| The EJB Command Design Pattern | 374 | |
| Session Bean Implementation Issues | 379 | |
| Error Handling in EJBs | 379 | |
| Transaction Attributes for EJBs using CMT | 382 | |
| The Business Methods Interface "Pattern" | 386 | |
| Session Beans in the Sample Application | 389 | |
| Summary | 389 | |
| Chapter 11 | Infrastructure and Application Implementation | 393 |
| Infrastructure | 394 | |
| Goals of a Strong Infrastructure | 395 | |
| Using a Framework to Configure Application Components | 396 | |
| Managing API Complexity | 410 | |
| Implementing Business Logic | 428 | |
| Implementing the Sample Application | 428 | |
| Summary | 437 | |
| Chapter 12 | Web-Tier MVC Design | 441 |
| The Challenges of Web Development | 442 | |
| Lessons Learned in Java Web Development | 443 | |
| The Shortcomings of Servlet-only Solutions | 443 | |
| JSP: Promise and Temptation | 444 | |
| Striking a Balance | 446 | |
| Web-Tier Design Goals | 447 | |
| A Clean Web Tier | 447 | |
| A Thin Web Tier | 447 | |
| MVC Concepts and the Front Controller J2EE Pattern | 448 | |
| Concepts | 449 | |
| Pattern Variants | 453 | |
| Implementation Goals | 455 | |
| Web Application Frameworks | 456 | |
| Common Concepts | 456 | |
| Available Frameworks | 457 | |
| Integrating a Web Application Framework into Overall Application Architecture | 465 | |
| The Web Application Framework Used in the Sample Application | 467 | |
| Design Goals | 468 | |
| Basic MVC Control Flow | 469 |
J2EE provides many architectural choices. J2EE also offers many component types (such as servlets, EJBs, JSP pages, and servlet filters), and J2EE application servers provide many additional services. While this array of options enables us to design the best solution for each problem, it also poses dangers. J2EE developers can be overwhelmed by the choices on offer, or can be tempted to use infrastructure inappropriate to the problem in hand, simply because it's available.
In this book I aim to help professional J2EE developers and architects make the appropriate choices to deliver high-quality solutions on time and within budget. I'll focus on those features of J2EE that have proven most useful for solving the commonest problems in enterprise software development.
In this chapter, we discuss the high-level choices in developing a J2EE architecture, and how to decide which parts of J2EE to use to solve real problems. We'll look at:
Distributed and non-distributed applications, and how to choose which model is appropriate
The implications for J2EE design of changes in the EJB 2.0 specification and the emergence of web services
When to use EJB
Data access strategies for J2EE applications
Four J2EE architectures, and how to choose between them
Web tier design
Portability issues
This book reflects my experience and discussions with other enterprise architects. I will attempt to justify the claims made in this chapter in the remainder of the book. However, there are, necessarily, many matters of opinion.
Familiarity with J2EE components has been assumed. We'll take a close look at container services in the following chapters, but please refer to an introductory book on J2EE if the concepts discussed are unfamiliar.
Goals of an Enterprise Architecture
Before we begin to examine specific issues in J2EE architecture, let's consider what we're trying to achieve.
A well-designed J2EE application should meet the following goals. Note that while we're focusing on J2EE-based solutions, these goals apply to all enterprise applications:
Be robust
Enterprise software is important to an organization. Its users expect it to be reliable and bugfree. Hence we must understand and take advantage of those parts of J2EE that can help us build robust solutions and must ensure that we write quality code.
Be performant and scalable
Enterprise applications must meet the performance expectations of their users. They must also exhibit sufficient scalability - the potential for an application to support increased load, given appropriate hardware. Scalability is a particularly important consideration for Internet applications, for which it is difficult to predict user numbers and behavior. Understanding the J2EE infrastructure is essential for meeting both these goals. Scalability will typically require deploying multiple server instances in a cluster. Clustering is a complex problem requiring sophisticated application server functionality. We must ensure that our applications are designed so that operation in a cluster is efficient.
Take advantage of OO design principles
OO design principles offer proven benefits for complex systems. Good OO design practice is promoted by the use of proven design patterns - recurring solutions to common problems. The concept of design patterns was popularized in OO software development by the classic book Design Patterns: Elements of Reusable Object-Oriented Software from Addison Wesley, (ISBN 0-201-63361-2), which describes 23 design patterns with wide applicability. These patterns are not technology-specific or language-specific.
It's vital that we use J2EE to implement OO designs, rather than let our use of J2EE dictate object design. Today there's a whole "J2EE patterns" industry. While many "J2EE patterns" are valuable, classic (non-technology-specific) design patterns are more so, and still highly relevant to J2EE.
Avoid unnecessary complexity
Practitioners of Extreme Programming (XP) advocate doing "the simplest thing that could possibly work". We should be wary of excessive complexity that may indicate that an application architecture isn't working. Due to the range of components on offer, it's tempting to over-engineer J2EE solutions, accepting greater complexity for capabilities irrelevant to the business requirements. Complexity adds to costs throughout the software lifecycle and thus can be a serious problem. On the other hand, thorough analysis must ensure that we don't have a naïve and simplistic view of requirements.
Be maintainable and extensible
Maintenance is by far the most expensive phase of the software lifecycle. It's particularly important to consider maintainability when designing J2EE solutions, because adopting J2EE is a strategic choice. J2EE applications are likely to be a key part of an organization's software mix for years, and must be able to accommodate new business needs. Maintainability and extensibility depend largely on clean design. We need to ensure that each component of the application has a clear responsibility, and that maintenance is not hindered by tightly-coupled components.
Be delivered on time
Productivity is a vital consideration, which is too often neglected when approaching J2EE.
Be easy to test
Testing is an essential activity throughout the software lifecycle. We should consider the implications of design decisions for ease of testing. Promote reuse
Depending on an application's business requirements, we may also need to meet the following goals:
Support for multiple client types There's an implicit assumption that J2EE applications always need to support multiple J2EE-technology client types, such as web applications, standalone Java GUIs using Swing or other windowing systems or Java applets. However, such support is often unnecessary, as "thin" web interfaces are being more and more widely used, even for applications intended for use within an organization (ease of deployment is one of the major reasons for this).
Portability How important is portability between resources, such as databases used by a J2EE application? How important is portability between application servers? Portability is not an automatic goal of J2EE applications. It's a business requirement of some applications, which J2EE helps us to achieve.
The importance of the last two goals is a matter of business requirements, not a J2EE article of faith. We can draw a dividend of simplicity that will boost quality and reduce cost throughout a project lifecycle if we strive to achieve only goals that are relevant.
Deciding Whether to Use a Distributed Architecture
J2EE provides outstanding support for implementing distributed architectures. The components of a distributed J2EE application can be split across multiple JVMs running on one or more physical servers. Distributed J2EE applications are based on the use of EJBs with remote interfaces, which enable the application server to conceal much of the complexity of access to and management of distributed components.
However, J2EE's excellent support for distributed applications has led to the misconception that J2EE is necessarily a distributed model.
It's often thought that a distributed model provides the only way to achieve robust, scalable applications. This is questionable. It's possible to cluster applications that collocate all their components in a single JVM.
Distributed architectures deliver the following benefits:
The ability to support many clients (possibly of different types) that require a shared "middle tier" of business objects. This consideration doesn't apply to web applications, as the web container provides a middle tier.
The ability to deploy any application component on any physical server. In some applications, this is important for load balancing. (Consider a scenario when a web interface does a modest amount of work, but business objects do intensive calculations. If we use a J2EE distributed model, we can run the web interface on one or two machines while many servers run the calculating EJBs. At the price of performance of each call, which will be slowed by the overhead of remote invocation, total throughput per hardware may be improved by eliminating bottlenecks.)
However, distributed architectures give rise to many tough problems, especially:
Performance problems
Remote invocations are many times slower than local invocations.
Complexity
Distributed applications are hard to develop, debug, deploy, and maintain.
Constraints on practicing OO design
This is an important point, which we'll discuss further shortly.
Distributed applications pose many interesting challenges. Due to their complexity, much of this book (and J2EE literature in general) is devoted to distributed J2EE applications. However, given a choice it's best to avoid the complexities of distributed applications by opting for a non-distributed solution.
New Considerations in J2EE Design
The J2EE 1.2 specification offered simple choices. EJBs had remote interfaces and could be used only in distributed applications. Remote Method Invocation (RMI) (over JRMP or IIOP) was the only choice for supporting remote clients.
Since then, two developments - one within J2EE and the other outside - have had profound implications for J2EE design:
The EJB 2.0 specification allows EJBs to have local interfaces, in addition to or instead of, remote interfaces. EJBs can be invoked through their local interfaces by components in an integrated J2EE application running in same JVM: for example, components of a web application.
The emergence of the XML-based Simple Object Access Protocol (SOAP) as a widely accepted, platform-agnostic standard for RMI, and widespread support for web services.
EJB 2.0 local interfaces were introduced largely to address serious performance problems with EJB 1.1 entity beans. They were a last-minute addition, after the specification committee had failed to agree on the introduction of "dependent objects" to improve entity bean performance. However, local interfaces have implications reaching far beyond entity beans. We now have a choice whether to use EJB without adopting RMI semantics.
While some of the bolder claims for web services, such as automatic discovery of services through registries, are yet to prove commercially viable, SOAP has already proven its worth for remote procedure calls. SOAP support is built into Microsoft's .NET, J2EE's leading rival, and may supersede platform-specific remoting protocols. The emergence of web services challenges traditional J2EE assumptions about distributed applications.
One of the most important enhancements in the next release of the J2EE specifications will be the integration of standard web services support. However, several excellent, easy-to-use, Java toolsets allow J2EE 1.3 applications to implement and access web services. See, for example, Sun's Java Web Services Developer Pack (java.sun.com/webservices/webservicespack.html) and the Apache Axis SOAP implementation (xml.apache.org/axis/index.html).
When to Use EJB
One of the most important design decisions when designing a J2EE application is whether to use EJB. EJB is often perceived to be the core of J2EE. This is a misconception; EJB is merely one of the choices J2EE offers. It's ideally suited to solving some problems, but adds little value in many applications.
When requirements dictate a distributed architecture and RMI/IIOP is the natural remoting protocol, EJB gives us a standard implementation. We can code our business objects as EJBs with remote interfaces and can use the EJB container to manage their lifecycle and handle remote invocation. This is far superior to a custom solution using RMI, which requires us to manage the lifecycle of server-side objects.
If requirements don't dictate a distributed architecture or if RMI/IIOP isn't the natural remoting protocol, the decision as to whether to use EJB is much tougher.
EJB is the most complex technology in J2EE and is the biggest J2EE buzzword. This can lead to developers using EJBs for the wrong reasons: because EJB experience looks good on a resume; because there is a widespread belief that using EJB is a best practice; because EJB is perceived to be the only way to write scalable Java applications; or just because EJB exists.
EJB is a high-end technology. It solves certain problems very well, but should not be used without good reason. In this section we'll take a dispassionate look at the implications of using EJB, and important considerations influencing the decision of whether to use EJB.
Implications of Using EJB
One of the key goals of the EJB specification is to simplify application code. The EJB 2.0 specification (§2.1) states that "The EJB architecture will make it easy to write applications: Application developers will not have to understand low-level transaction and state management details, multi-threading, connection pooling, and other complex low-level APIs."
In theory, by deferring all low-level issues to the EJB container, developers are free to devote all their effort to business logic. Unfortunately, experience shows that this is not often realized in practice. Using EJB often adds at least as much complexity to an application as it removes. Moreover, it may be dangerous for developers to "not have to understand" the enterprise software issues that their applications face.
(Continues...)
Excerpted from Expert One-on-One J2EE Design and Development by Rod Johnson Excerpted by permission.
All rights reserved. No part of this excerpt may be reproduced or reprinted without permission in writing from the publisher.
Excerpts are provided by Dial-A-Book Inc. solely for the personal use of visitors to this web site.
loading...
loading...
loading...
Terms of Use, Copyright, and Privacy Policy
© 1997-2009 Barnesandnoble.com llc