SlideShare a Scribd company logo
Testing Java Microservices Using Arquillian
Hoverfly Assertj Junit Selenium And Mockito
First Edition Alex Soto Bueno download
https://ebookbell.com/product/testing-java-microservices-using-
arquillian-hoverfly-assertj-junit-selenium-and-mockito-first-
edition-alex-soto-bueno-55587642
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Testing Java Microservices Using Arquillian Hoverfly Assertj Junit
Selenium And Mockito 1st Edition Andy Gumbrecht
https://ebookbell.com/product/testing-java-microservices-using-
arquillian-hoverfly-assertj-junit-selenium-and-mockito-1st-edition-
andy-gumbrecht-7261950
Java Testing With Spock Konstantinos Kapelonis Luke Daley
https://ebookbell.com/product/java-testing-with-spock-konstantinos-
kapelonis-luke-daley-5470386
Java Testing Design And Automation Illustrated Edition Frank Cohen
https://ebookbell.com/product/java-testing-design-and-automation-
illustrated-edition-frank-cohen-974486
Java Testing With Selenium A Comprehensive Syntax Guide For Automation
https://ebookbell.com/product/java-testing-with-selenium-a-
comprehensive-syntax-guide-for-automation-57865422
Testng Java Testing Framework Tutorials Point
https://ebookbell.com/product/testng-java-testing-framework-tutorials-
point-12142790
Next Generation Java Testing Testng And Advanced Concepts Beust
https://ebookbell.com/product/next-generation-java-testing-testng-and-
advanced-concepts-beust-22041386
Penetration Testing With Java A Stepbystep Pen Testing Handbook For
Java Applications Nancy Snoke
https://ebookbell.com/product/penetration-testing-with-java-a-
stepbystep-pen-testing-handbook-for-java-applications-nancy-
snoke-232021524
Unit Testing In Java How Tests Drive The Code 1st Edition Johannes
Link
https://ebookbell.com/product/unit-testing-in-java-how-tests-drive-
the-code-1st-edition-johannes-link-979056
Pragmatic Unit Testing In Java 8 With Junit Jeff Langr Andy Hunt
https://ebookbell.com/product/pragmatic-unit-testing-in-java-8-with-
junit-jeff-langr-andy-hunt-38623494
Testing Java Microservices Using Arquillian Hoverfly Assertj Junit Selenium And Mockito First Edition Alex Soto Bueno
Testing Java Microservices Using Arquillian Hoverfly Assertj Junit Selenium And Mockito First Edition Alex Soto Bueno
Copyright
For online information and ordering of this and other Manning books, please visit
www.manning.com. The publisher offers discounts on this book when ordered in
quantity. For more information, please contact
Special Sales Department
Manning Publications Co.
20 Baldwin Road
PO Box 761
Shelter Island, NY 11964
Email: orders@manning.com
©2018 by Manning Publications Co. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or
transmitted, in any form or by means electronic, mechanical, photocopying, or
otherwise, without prior written permission of the publisher.
Many of the designations used by manufacturers and sellers to distinguish their
products are claimed as trademarks. Where those designations appear in the book, and
Manning Publications was aware of a trademark claim, the designations have been
printed in initial caps or all caps.
Recognizing the importance of preserving what has been written, it is Manning’s
policy to have the books we publish printed on acid­free paper, and we exert our best
efforts to that end. Recognizing also our responsibility to conserve the resources of our
planet, Manning books are printed on paper that is at least 15 percent recycled and
processed without the use of elemental chlorine.
ayl sts
story
opics
torials
fers & Deals
ghlights
ttings
Support
Sign Out
Manning Publications Co.
20 Baldwin Road
PO Box 761
Shelter Island NY 11964
,
Development editor: Cynthia Kane
Technical development editor: Adam Scheller
Project editor: Tiffany Taylor
Copyeditor: Tiffany Taylor
Proofreader: Katie Tennant
Technical proofreader: Joshua White
Typesetter: Gordan Salinovic
Cover designer: Marija Tudor
ISBN 9781617292897
Printed in the United States of America
1 2 3 4 5 6 7 8 9 10 – DP – 23 22 21 20 19 18
Brief Table of Contents
Copyright
Brief Table of Contents
Chapter 1. An introduction to microservices
Chapter 2. Application under test
Chapter 3. Unit­testing microservices
Chapter 4. Component­testing microservices
Chapter 5. Integration­testing microservices
Chapter 6. Contract tests
Chapter 7. End­to­end testing
Chapter 8. Docker and testing
Chapter 9. Service virtualization
Chapter 10. Continuous delivery in microservices
Playlists
History
Topics
Tutorials
Appendix. Masking multiple containers with Arquillian Chameleon
Chapter 1. An introduction to microservices
This chapter covers
Why move toward a new microservice architecture?
What microservices are today, and where the future may lead
The basic component makeup of a microservice
Testing strategies
Traditional monolithic applications are deployed as a single package, usually as a web
or enterprise­archive file (WAR or EAR). They contain all the business logic required to
complete multiple tasks, often alongside the components required to render the user
interface (UI, or GUI for graphical user interface). When scaling, this usually means
taking a complete copy of that entire application archive onto a new server node
(basically, deploying it to another server node in a cluster). It doesn’t matter where the
load or bottleneck is occurring; even if it’s only in a small cross section of the
application, scaling this way is an all­or­nothing approach. Microservices are
specifically designed to target and change this all­or­nothing aspect by allowing you to
break your business logic into smaller, more manageable elements that can be
employed in multiple ways.
This book isn’t intended to be a tutorial on the varied microservice architectures that
are available today; we’ll assume you have some understanding of the subject. Rather,
we’re going to help you overcome the challenges involved in testing the common
features that all microservice applications share. In order to do that, in this chapter
we’ll establish some common ground about what a microservice is, so that you can
relate to where we’re coming from when we discuss these topics in later chapters.
Shifting toward the ever­more­popular microservice architecture means you need to
adopt new strategies in development, testing, and restructuring/refactoring and move
away from some of the purely monolithic­application practices.
Microservices offer you the advantage of being able to scale individual services, and the
Playlists
History
Topics
Tutorials
Offers & Deals
Highlights
Settings
Support
Sign Out
ability to develop and maintain multiple services in parallel using several teams, but
they still require a robust approach when it comes to testing.
In this book, we’ll discuss various approaches for using this new, more focused way of
delivering tightly packaged “micro” services and how to resolve the complex testing
scenarios that are required to maintain stability across multiple teams. Later chapters
will introduce an example application and how to develop testing strategies for it; this
will help you better understand how to create your own test environments.
You’ll see and use many features of the Arquillian test framework, which was
specifically designed to tackle many of the common testing challenges you’ll face. An
array of mature extensions have been developed over the years, and although other
tools are available, Arquillian is our tool of choice—so expect some bias. That said,
Arquillian also provides close integration with many testing tools you may already be
familiar with.
A note about software versions
This book uses many different software packages and tools, all of which change
periodically. We tried throughout the book to present examples and techniques that
wouldn’t be greatly affected by these changes. All examples require Java 8, although
when we finished the book, Java 10 had been released. We haven’t updated the
examples because in terms of testing microservices, the release doesn’t add anything
new. Something similar is true for JUnit 5. All of the examples are written using JUnit
4.12, because when we started writing the book, JUnit 5 wasn’t yet in development. At
the time we finished the book, not all of the frameworks explained here have official
support for JUnit 5, so we decided to skip updating the JUnit version. Other libraries,
such as Spring Boot and Docker (Compose), have evolved as well during the
development of the book, but none of these changes have a significant impact on how to
write tests.
1.1. WHAT ARE MICROSERVICES, AND WHY USE THEM?
In this section, we present what we believe is a reasonably good interpretation of the
currently available answers to these questions. What you learn will provide a solid basis
for understanding the microservice architecture, but expect innovation over time. We
won’t make any predictions: as stated, our principle focus for the book is testing
microservices, which is unlikely to change in any significant way.
It isn’t important that you fully understand the microservice architecture at this point.
But if, after reading this chapter, the term microservice is still a dark void for you, we
encourage you to gather more information from your own sources.
Tip
You may find it useful to join the open discussions at MicroProfile
(http://microprofile.io). This is an initiative by the likes of IBM, London Java Community
(LJC), RedHat, Tomitribe, Payara, and Hazelcast to develop a shared definition of
Enterprise Java for microservices, with the goal of standardization.
1.1.1. Why use microservices?
Before we delve into the nature of microservices, let’s answer the “why” question. Until
recently, it’s been commonplace to develop monolithic applications, and that’s still
perfectly acceptable for any application that doesn’t require scaling. The problem with
scaling any kind of monolithic application is straightforward, as shown in figure 1.1.
Microservices aren’t here to tell you that everything else is bad; rather, they offer an
architecture that is far more resilient than a monolith to changes in the future.
Figure 1.1. Scaling a monolithic application
Microservices enable you to isolate and scale smaller pieces of your application, rather
than the entire application. Imagine that you’ve extracted some core business logic in
your application to services A and B. Let’s say service A provides access to an inventory
of items, and B provides simple statistics. You notice that on average, service A is called
one million times per hour and service B is called only once per day. Scaling a
monolithic application would mean adding a new node with the application that
includes both services A and B.
Wouldn’t it be better if you only needed to scale service A? This is where the potential of
microservices becomes apparent: in the new architecture, shown in figure 1.2, services A
and B become microservices A and B. You can still scale the application, but this
additional flexibility is the point: you can now choose to scale where the load is greatest.
Even better, you can dedicate one team of developers to maintaining microservice A
and another to microservice B. You don’t need to touch the application to add features
or fix bugs in either A or B, and they can also be rolled out completely independently of
each other.
Figure 1.2. Scaling a microservice independently of the main application
Companies like Netflix, Google, Amazon, and eBay have based much of their platforms
on a microservice architecture, and they’ve all been kind enough to share much of this
information freely. But although considerable focus is placed on web applications, you
can apply a microservice architecture to any application. We hope this whets your
appetite!
1.1.2. What are microservices?
At first glance, the term micro may conjure up images of a tiny application with a small
footprint. But regarding application size, there are no rules, other than a rule of thumb.
A microservice may consist of several, several hundred, or even several thousand lines
of code, depending on your specific business requirements; the rule of thumb is to keep
the logic small enough for a single team to manage. Ideally, you should focus on a single
endpoint (which may in turn provide multiple resources); but again, there’s no hard­
and­fast rule. It’s your party.
The most common concept is that a single application should be the uppermost limit of
a microservice. In the context of a typical application server running multiple
applications, this means splitting applications so they’re running on a single application
server. In theory, think of your first microservice as a single piece of a jigsaw puzzle,
and try to imagine how it will fit together with the next piece.
You can break a monolithic application into its logical pieces, as shown in figure 1.3.
There should be just enough information within each piece of the puzzle to enable you
to build the greater picture. In a microservice architecture, these pieces are much more
loosely coupled; see figure 1.4.
Figure 1.3. Each service is part of the big picture.
Figure 1.4. Each microservice is still part of the picture but is isolated within a
separate environment.
1.1.3. Continuous integration, deployment, and Docker
The decoupling of application elements into scalable microservices means you’ll have to
start thinking about the continuous integration (CI) and continuous delivery (CD)
pipelines from an early stage. Instead of one build script and one deployment, you’ll
need multiple independent builds that must be sewn together for integration testing
and deployment to different hosts.
You’ll find that far less work is involved than you may think. This is largely due to the
fact that a microservice is, for all intents and purposes, an application like any other.
The only difference is that a microservice packages the application together with its
runtime environment. The easiest and most recognized way to do this today is to create
and deploy a microservice as a Docker image (www.docker.com).
Note
Docker is the world’s leading software­containerization platform. If you’re not sure
what Docker is, then at some point please visit www.docker.com and follow the “What is
Docker?” tutorial. Don’t worry, though—we’ll guide you through this pipeline when we
put all the microservice elements together toward the end of the book.
The heavyweight CI/CD contenders are Travis (https://travis­ci.org), Bamboo
(https://de.atlassian.com/software/bamboo), and Jenkins (https://jenkins.io). They all provide
great support for microservices and deployment pipelines for Docker images; but in
this book, we’ll use Jenkins, because it’s open source and has a huge community. It’s
not necessarily the easiest to use, but it offers by far the most features via plugins. In
chapter 8, we’ll highlight all the involved technologies in detail and guide you through
the development of a viable CI/CD pipeline.
1.2. MICROSERVICE NETWORKS AND FEATURES
Microservices are loosely coupled, which leads to new questions. How are
microservices coupled, and what features does this architecture offer? In the following
sections, we’ll look at some answers. But for all intents and purposes, each microservice
is isolated by a network boundary.
1.2.1. Microservice networks
Microservices are most commonly integrated over a RESTful (Representational State
Transfer) API using HTTP or HTTPS, but they can be connected by anything that’s
considered a protocol to access an endpoint to a resource or function. This is a broad
topic, so we’re only going to discuss and demonstrate Java REST using JAX­RS.
Tip
If you’re unfamiliar with RESTful web services using JAX­RS (https://jax­rs­
spec.java.net), now would be a good time to read up on these topics.
With this information, your initial ideas for microservices should be starting to take
form. Let’s continue with our earlier example. Microservice A, the inventory service, is
isolated by a network layer from the UI and from microservice B, the statistics service.
B communicates with A to collect statistics using the defined request­and­response
protocols. They each have their own domain and external resources and are otherwise
completely separate from each other. The UI service is able to call both A and B to
present information in a human­readable form, a website, or a heavy client, as shown in
figure 1.5.
Figure 1.5. Each service communicates by defined protocols.
Hypermedia
Services should be developed with hypermedia in mind. This is the latest buzzword; it
implies that services should be self­documenting in their architecture, by providing
links to related resources in any response. Currently there’s no winner in this category,
and it would be unfair to start placing bets now, but you can take a look at the front
runners and make an educated guess: JSON­LD (http://json­ld.org), JSON Hypertext
Application Language (HAL, https://tools.ietf.org/html/draft­kelly­json­hal­08),
Collection+JSON (https://github.com/collection­json/spec), and Siren
(https://github.com/kevinswiber/siren).
Tests must be designed to cover comprehensively any and all interaction with external
services. It’s important to get this right, because network interaction will always present
its own set of challenges. We’ll cover this extensively in chapter 5.
By now it should be clear that a microservice can be large in terms of application size,
and that “micro” refers to the public­facing surface area of the application. Cloud space
is cheap today, so the physical size of a microservice is less relevant than in the past.
Another concern that we often hear mentioned is, “What about network speed?”
Microservices are generally hosted in the same local network, which is typically Gigabit
Ethernet or better. So, from a client perspective, and given the ease of scaling
microservices, response times are likely to be much better than expected. Again, don’t
take our word for it; think of Netflix, Google, Amazon/AWS, and eBay.
1.2.2. Microservice features
In our example, both microservices A and B can be developed independently and
deployed by two entirely different teams. Each team only needs to understand the
resource­component layer of the microservice on which they’re working, rather than
the entire business­domain component. This is the first big win: development can be
much faster and easier to understand in the given context.
JavaScript Object Notation (JSON, www.json.org) and Extensible Markup Language
(XML, www.w3.org/XML) are the common resource languages, so it’s easy to write
clients for such services. Some cases may dictate a different approach, but the basic
scenarios remain essentially the same: the endpoints are accessible from a multitude of
devices and clients using defined protocols.
Multiple microservices form a network of connected applications, where each
individual microservice can be scaled independently. Elastic deployment on the cloud is
now commonplace, and this enables an individual service to scale automatically up or
down—for example, based on load.
Some other interesting benefits of microservices are improved fault isolation and
memory management. In a monolithic application, a fault in a single component can
bring down an entire server. With resilient microservices, the larger part of the picture
will continue to function until the misbehaving service issue is resolved. In figure 1.6, is
the statistics service really necessary for the application to function as a whole, or can
you live without it for a while?
Figure 1.6. Resilient design using circuit breakers
Of course, as is the nature of all good things, microservices have drawbacks. Developers
need to learn and understand the complexities of developing a distributed application,
including how best to use IDEs, which are often orientated toward monolithic
development. Developing use cases spanning multiple services that aren’t included in
distributed transactions requires more thought and planning than for a monolith. And
testing is generally more difficult, at least for the connected elements, which is why we
wrote this book.
1.3. MICROSERVICE ARCHITECTURE
The anatomy of a microservice can be varied, as shown in figure 1.7, but design
similarities are bound to occur. These elements can be grouped together to form the
application­component layers. It’s important to provide test coverage at each layer, and
you’ll likely be presented with new challenges along the way; we’ll address these
challenges and offer solutions throughout the book.
Figure 1.7. The basic microservice components
Let’s look at these microservice component layers from the top down.
Note
A microservice should encapsulate and expose a well­defined area of logic as a service.
That doesn’t mean that you can’t allow interaction from other systems by other means.
For example, your service may expose specific documents that are stored in
Elasticsearch (ES). In such a case, it’s perfectly legitimate for other applications to talk
natively to ES in order to seed the documents.
1.3.1. Resource component
Resources are responsible for exposing the service interaction via a chosen protocol.
This interaction occurs using mapped objects, usually serialized using JSON or XML.
These mapped objects represent the input and/or output of the business domain.
Sanitization of the incoming objects and construction of the protocol­specific response
usually occur at this layer; see figure 1.8.
Figure 1.8. The resource component publicly exposes the service.
Note
Now that we’re here, it’s worth mentioning that the resource­component layer is the
layer that puts the micro in microservice.
For the rest of this book, and for the sake of simplicity, we’ll focus on the most common
form of resource providers today: RESTful endpoints. If you aren’t familiar with
RESTful web services, please take the time to research and understand this important
topic.
See “What Are RESTful Web Services?” in the Java EE 6 tutorial, http://mng.bz/fIa2.
1.3.2. Business-domain component
The business­domain component is the core focus of your service application and is
highly specific to the logical task for which the service is being developed. The domain
may have to communicate with various other services (including other microservices)
in order to calculate a response or process requests to and from the resource
component; see figure 1.9.
Figure 1.9. The business-domain component is your service’s business logic.
A bridge is likely to be required between the domain component and the resource
component, and possibly the remote component. Most microservices need to
communicate with other microservices at some point.
1.3.3. Remote resources component
This component layer is where your piece of the jigsaw puzzle may need to connect to
the next piece, or pieces, of the picture. It consists of a client that understands how to
send and receive resource objects to and from other microservice endpoints, which it
then translates for use in the business component layer; see figure 1.10.
Figure 1.10. The remote resources component is the gateway to other services.
[ 1 ]
1
Due to the nature of remote resources, you must pay special attention to creating a
resilient design. A resilient framework is designed to provide features such as circuit
breakers and timeout fallbacks in the event of a failure. Don’t try to reinvent the wheel:
several resilient frameworks are available to choose from, including our top pick,
Hystrix (https://github.com/Netflix/Hystrix/wiki), which is open source and contributed by
Netflix.
A gateway service should act as a bridge between the domain component and the client
component. It’s responsible for translating request­and­response calls to and from any
remote resource via the client. This is the best place to provide a graceful failure if the
resource can’t be reached.
The client is responsible for speaking the language of your chosen protocol. Nine times
out of ten, this will be JAX­RS (https://jax­rs­spec.java.net) over HTTP/S for RESTful web
services.
We highly recommend the open source services framework Apache CXF
(http://cxf.apache.org) for this layer, because it’s fully compliant with JAX­WS, JAX­RS,
and others, and it won’t tie you down to a specific platform.
1.3.4. Persistence component
More often than not, an application requires some type of persistence or data retrieval
(see figure 1.11). This usually comes in the form of an object­relational mapping (ORM)
mechanism, such as the Java Persistence API (JPA), but could be something as
simple as an embedded database or properties file.
See “Hibernate ORM: What Is Object/Relational Mapping?” http://hibernate.org/orm/what­is­an­orm.
See “Introduction to the Java Persistence API” in the Java EE 6 tutorial, http://mng.bz/Cy69.
Figure 1.11. The persistence component is for data storage.
[
2 ] [ 3 ]
2
3
1.4. MICROSERVICE UNIT TESTING
Chapter 3 will take a deep dive into real unit­testing scenarios. The next few paragraphs
are an introduction to the terminology we’ll use and what to expect as you develop your
testing strategies.
A typical unit test is designed to be as small as possible and to test a trivial item: a unit
of work. In the microservice context, this unit of work may be more difficult to
represent, due to the fact that there’s often much more underlying complexity to the
service than is apparent at first glance.
Unit testing can often lead to the conclusion that you need to refactor your code in
order to reduce the complexity of the component under test. This also makes testing
useful as a design tool, especially when you’re using test­driven development (TDD). A
beneficial side effect of unit testing is that it lets you continue developing an application
while detecting regressions at the same time.
Although you’re likely to encounter more­detailed scenarios along the way, there are
basically two styles of unit testing: sociable and solitary. These styles are loosely based
on whether the unit test is isolated from its underlying collaborators. Both styles are
nonexclusive, and they complement each other nicely. You should count on using both,
depending on the nature of the testing challenge. We’ll expand on these concepts
throughout the book.
1.4.1. Solitary unit tests
Solitary unit testing should focus on the interaction around a single object class. The
test should encompass only the class’s own dependents or dependencies on the class.
You’ll usually test resource, persistence, and remote components using solitary tests,
because those components rarely need to collaborate with each other; see figure 1.12.
Figure 1.12. Predominantly solitary unit-test components
You need to isolate individual classes for testing by stubbing or mocking all
collaborators within that class. You should test all the methods of the class, but not
cross any boundaries to other concrete classes. Basically, this means all injected fields
should receive either a mock or stubbed implementation that only returns canned
responses. The primary aim is for the code coverage of the class under test to be as high
as possible.
1.4.2. Sociable unit tests
Sociable unit testing focuses on testing the behavior of modules by observing changes
in their state. This approach treats the unit under test as a black box tested entirely
through its interface. The domain component is nearly always a candidate for sociable
testing, because it needs to collaborate in order to process a request and return a
response; see figure 1.13.
Figure 1.13. Predominantly sociable unit-test component
You may still need to stub or mock some complex collaborators of the class under test,
but this should be as far along as possible within the hierarchy of collaborating objects.
You shouldn’t only be testing that a specific class sends and receives correct payloads,
but also that the class collaborators are operating as expected within the class. The test
coverage should ideally include all models, variables and fields as well as the class
collaborators. It’s also important to test that the class can correctly handle any
response, including invalid responses (negative testing).
SUMMARY
A microservice is a part of a monolithic application that has been dissected into a
smaller logical element.
Microservices benefit your application by allowing targeted scaling and focused
development.
Microservices offer a logical way to meet scalability requirements by providing the
ability to scale not only where performance is required, but also when.
You can break monolithic applications into smaller elements that can be used as
microservices.
Microservices allow several teams to focus on individual, nonconflicting tasks that
make up the bigger picture.
Solitary unit tests are used for components that don’t store state or don’t need to
collaborate in order to be tested.
Sociable unit tests are used for components that must collaborate or store state in
order to be tested.
Chapter 2. Application under test
This chapter covers
Exploring a sample application
Understanding critical parts of the code
Developing microservices with Java EE and Spring Boot
The previous chapter introduced you to microservices, including their basic anatomy
and architecture. This introduction was intended to give you insight into the kinds of
tests you might need to write for a microservice­based architecture.
This chapter introduces the application that will be used throughout the book to
demonstrate the development and testing of a microservices architecture. Our goal is to
provide an easy­to­follow example that will help you understand the relevance of each
kind of test that will be applied. We try to follow best practices for a microservices
architecture, but we make some design choices for the sake of simplicity and also purely
for educational purposes. For instance, we may use more technologies than necessary,
or simplify the number of layers used in a microservice because they don’t add value
from a testing point of view. In such cases, we point out the reason for a particular
approach and discuss how to perform these tasks in real­world programming. It’s
ultimately your responsibility as a developer to choose the appropriate tools to use, but
we always offer a recommended approach.
2.1. GETTING STARTED
The example application, Gamer, is a simple software portal for gamers. Its purpose is
to expose information about software games and to let gamers not only read important
facts about games and watch videos of games being played, but also comment on and
leave a star rating for played games. Although this application is intentionally simple, it
covers all the main topics needed to showcase the microservices architecture.
Throughout the book, we’ll guide you through the various kinds of tests to be written
for a microservices­based application.
Playlists
History
Topics
Tutorials
Offers & Deals
Highlights
Settings
Support
Sign Out
We’ll start by providing some use cases for the Gamer app, to get a high­level view of
the actions a gamer can take. Gamers want to be able to do these things:
Search for games by name, so they can see a list of games that match their interests
Read about important aspects of a game, such as its publication date and which
platforms are supported
Read other gamers’ comments about a game, to help them decide whether they’ll
enjoy it and want to buy it
Write comments about a game, so other gamers can benefit from their evaluation of
it
Assign a star rating to a game and quickly see the games with the highest ratings
Watch game­related videos such as trailers, tutorials, and real in­game play
Let’s begin by defining the data required for this application. We won’t focus on
technical details just yet—this section only describes the conceptual data model.
The main entity is a game. Table 2.1 shows the parts that make up a game.
Table 2.1. The parts of a game
Field Description
title String representing the name of the game
cover URL of an image of the game cover
ReleaseDate The game’s release date
Publisher The game’s publisher
Developer The game’s developer
Table 2.2 shows the parts that make up a release date.
Table 2.2. Parts of a release date
Field Description
platform Platform name under which the game was released
date
Date (day, month, and year) when the game was released
for a platform
Table 2.3 shows the parts that make up a comment.
Table 2.3. Parts of a comment
Field Description
comment String containing the comment message
rate
Star rating from 1 to 5, indicating the overall quality of the
game
Now that you understand the kinds of data the Gamer app will manage, we can go a
little deeper and inspect the architecture of the application.
2.2. PREREQUISITES
This book isn’t a Java tutorial. If you’re not already familiar with Java as a language,
then you’re highly unlikely to have an enjoyable read. That said, we hope to present
information that’s of use to readers with all levels of interest. The Java tutorials at
https://docs.oracle.com/javase/tutorial are outstanding resources for any aspiring Java
developer and a fantastic reference for everyone who uses Java.
The book also isn’t an academic masterpiece. The authors are primarily developers, and
English isn’t the first language for some of us. We like getting our hands dirty, and we
hope you do too. We expect you to bring an open mind and understand that not
everyone may share our opinions. There’s never one way that’s entirely right or entirely
wrong, and our suggestions are presented as food for thought for your creative mind.
Note
Much of the source code is formatted based on the restrictions of presenting it on a
printed page. This can lead to verbose layout. Feel free to adjust the code formatting to
your own preferences.
2.2.1. Java Development Kit
You’ll need at least version SE (Standard Edition) 8 of the Java Development Kit (JDK)
to compile and run the code in this book. You can always find the latest Oracle JDK
(recommended) at http://mng.bz/83Ct or the OpenJDK at http://openjdk.java.net.
To test for Java, run the following command, which should display results similar to the
following, depending on your installed version:
$ java ­version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121­b13)
Java HotSpot(TM) 64­Bit Server VM (build 25.121­b13, mixed mode)
2.2.2. Build tools
We’re using both Apache Maven (https://maven.apache.org) and Gradle (https://gradle.org)
to build several of the project modules. Make sure you’ve installed both of these tools by
following the instructions provided on the corresponding websites.
To test for a correct Maven installation, run the following command:
$ mvn ­version
Apache Maven 3.3.9
...
For Gradle, run this command:
$ gradle ­v
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Gradle 3.2.1
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
2.2.3. Environment variables
The full application requires two API keys in order to access some remote resources.
The API keys are registered to individual user accounts, so we can’t provide shared keys
here.
It’s not necessary to obtain these keys in order to run most of the test examples
provided in this book. But if you wish to experiment with the code, we suggest that you
obtain the keys and create the corresponding environment variables. To obtain an API
key for YouTube, visit https://developers.google.com/youtube/v3/getting­started and follow
the instructions in the Before You Start section. To obtain an API key for the Internet
Game Database (IGDB), visit https://igdb.github.io/api/about/welcome or go directly to
https://api.igdb.com to register for access.
Once you have your own API keys, add them to your environment variables. On Linux,
add the following in /home/profile:
...
export YOUTUBE_API_KEY="Your­Key"
export IGDB_API_KEY="YourKey"
Windows users may find the following link useful for configuring environment
variables: http://mng.bz/1a2K.
William R. Stanek, “Configuring System and User Environment Variables,” MSDN, from Microsoft Windows
2000 (Microsoft Press, 2002).
2.2.4. Integrated development environment (IDE)
None of the application code requires you to use an IDE. Notepad will do.
Of course, feel free to open the projects using your favorite IDE (that supports Maven­
and Gradle­based projects). If you want to add breakpoints in the code in order to
follow the execution path (highly recommended), then we suggest using an IDE.
We’ve tested the code in the following IDEs, in no particular order of preference:
IntelliJ IDEA (www.jetbrains.com/idea)
NetBeans (https://netbeans.org)
Eclipse (www.eclipse.org/downloads)
2.3. ARCHITECTURE
As mentioned at the beginning of the chapter, the Gamer app follows a microservices
architecture. The first thing to do is identify which services make up the application.
For this app, we concluded that splitting the domain into four distinct microservices
was required:
Game service—Provides all the information related to games. It includes queries for
obtaining a game ID by a specific name, or returns information for a specific game
ID.
Comments service—Adds star ratings and comments for a specific game, as well as
retrieves them.
Video service—Returns the location of the three most prominent videos for a game.
Aggregator service—Calls the aforementioned named services, and aggregates the
data of each service into a single response.
[ 1 ]
1
The application schema is shown in figure 2.1.
Figure 2.1. Gamer application schema
As you can see, a frontend (typically a browser) consumes the information provided by
the Gamer API. The point of entry is the aggregator service, which communicates with
the game, video, and comments services to get or insert required data for games. The
aggregator service compiles all the data into a single response and returns this to the
frontend. You can now understand the application architecture and the technical
reasons behind the decisions that were made for each service.
Note
At first, please skip the tests when you build the application from the command line or
IDE. To demonstrate a point, and also to provide exercises, some of the tests won’t
complete as provided. As your knowledge builds throughout the book, you’ll be in a
better position to play with and expand the sample code.
2.3.1. The game service
Install the game service using the following code:
cd ./game
mvn install ­DskipTests
The game service is a Java EE 7 application running on WildFly Swarm that’s
responsible for providing all the information related to games. It provides two
operations to retrieve this information:
Getting a list of games by title (multiple games can have the same title). The
information provided for this endpoint must be minimal: for example, only the
identifier and/or title of the game.
Returning detailed information about a game by specifying a known game
identifier.
You might have noticed that there’s no operation for inserting games. This is because
the game service acts as a proxy/cache to an external service API. An external service is
a service that’s out of the current application scope, that’s developed and maintained by
a third party, and to which you’re merely a subscriber. Typical examples of these
services are search engines, weather forecasts, and geospatial calculations.
This service example relies on the Internet Game Database website (www.igdb.com) to
provide all of the required game data.
The Internet Game Database API
IGDB is a video game database, intended for use by both game consumers and video
game professionals. In addition to serving as a portal for getting information about
games, the site provides a public REST API (www.igdb.com/api) that lets you access data
for games registered on the site.
To authorize access to the REST API, you need to register on the site and request a new
API key. This key must be passed in each call as an HTTP header.
During the course of the book, we provide more information about the IGDB REST API,
such as how to authenticate against IGDB, and the required format for resource
endpoints.
When you rely on external calls to third­party services, it’s always important (if
possible) to cache as much data from the external service as you can. This is important
for three reasons:
You avoid round trips to external networks, which is typically a slow operation.
If you have quota/metered access to the external API, you save on hits to the
service.
In the event the external service experiences an outage, your application can
continue to work with cached data.
Warning
Generally, caching is used only in cases where the external data doesn’t change often or
you can replicate all the data on your systems. To maintain coherence of the external
data, you should apply a periodic refresh strategy to the cache so it doesn’t become
outdated. For the sake of simplicity, no refresh strategy is implemented in the example
app, but this is something to take into consideration in a real­world scenario.
In this microservice, a cache­persistence­layer system is implemented using the light
SQL database H2 (www.h2database.com/html/main.html). The entity­relationship (ER)
model used in the game service is composed of four entities, described in tables 2.4–2.7.
Figure 2.2 shows this in graphical terms.
Table 2.4. Game table
Field Data type Description
id Long Game identifier.
version Int
Internal field for avoiding conflicts in
optimistic locking.
title String Name of the game. This value is unique.
cover String
URL of the cover of the game, or null if no
cover.
Release dates ReleaseDate
One­to­many relationship of type
ReleaseDate.
Publishers Collection of Strings
One­to­many relationship between
publishers and the name of the game.
Developer Collection of Strings
One­to­many relationship between
developers and the name of the game.
Table 2.5. ReleaseDate table
Field Data type Description
OwnerId Long
Identifier for the game. This field acts as a
foreign key.
platformName String
Platform name under which game was
released.
releaseDate String
Date when the game was released for this
platform, in YYYY/MM/DD format.
Table 2.6. Publisher table
Field Data type Description
OwnerId Long
Identifier for the game. This field acts as a
foreign key.
publisherName String Publisher name.
Table 2.7. Developer table
Field Data type Description
OwnerId Long
Identifier for the game. This field acts as a
foreign key.
developer String Developer name.
Figure 2.2. Gamer application entity relationship
The entity­relationship schema in figure 2.2 shows that a game is composed of a title
and a cover, is made by one­to­n (one­to­many) developers, is published by one or
many publishers, and has zero or more release dates for each platform.
Note
There are other options that are a good fit for caching data for microservice
architectures, such as Infinispan, Hazelcast, and Redis. They not only offer time­to­live
(TTL) features, which makes the refresh logic much simpler, but also work in
distributed (clustered) environments, which is typical in microservice architectures. For
teaching purposes, in this book we use a SQL database. This approach is simple and
uses a technology that you may be accustomed to. This also allows us to introduce an
important feature: persistence testing of the ORM.
On the server layer, the game service runs on the WildFly Swarm application server. An
overall schema of this service is shown in figure 2.3. The persistence layer uses an H2
SQL database for storing and retrieving cached data for games. Finally, the service
connects to the external site (IGDB.com) to obtain information for games that aren’t yet
cached on the system.
Figure 2.3. Game service overview
WildFly Swarm
WildFly Swarm (http://wildfly­swarm.io) offers an approach to packaging and running
Java EE applications by generating an uber­JAR (java ­jar MyApp.jar), which
packages the application with just enough of the server runtime to run.
It also has built­in support for applications and frameworks such as Logstash, Netflix
projects like Hystrix and Ribbon, and Red Hat projects like Keycloak and Hawkular.
2.3.2. The comments service
2.3.2. The comments service
Build and package the comments service using the following code:
cd ./comments
./gradlew war ­x test
The comments service is an EE 7 application running on Apache TomEE. It’s
responsible for managing comments for a specific game, as well as the game rating. A
rating is a number between 1 (the lowest rating) and 5 (the highest rating). Notice that
this feature isn’t provided by IGDB; it’s something you’ll add to the portal to make it
more participatory. This service provides two endpoints:
One adding a comment and a game rating
A second that returns all the comments that have been written for a game, along
with the average game rating
The persistence layer for this service uses a document­oriented NoSQL database for
storing all the data required by the service. We chose the MongoDB NoSQL database
specifically due to its out­of­the­box aggregation framework. It’s a perfect solution for
calculating the average rating for a given game.
Note
Similar logic could be implemented using a traditional SQL database, but nowadays it’s
not uncommon to use a NoSQL database due to its better performance in certain
circumstances. This service uses a NoSQL database to showcase the example.
MongoDB
MongoDB is a document­oriented NoSQL database. Instead of using a relational
database structure, MongoDB stores JSON­like documents with dynamic schemas in
collections. Documents that have a similar purpose are stored in the same collection.
You can think of a collection as being equivalent to an RDBMS table, but without
forcing a schema.
In addition to storing documents, MongoDB provides features like indexing,
replication, load balancing with horizontal shards, and an aggregation framework.
MongoDB structures documents into collections. For the comments service, this
collection is named comments. Each document that represents a comment has a
schema like the following and contains the game’s ID, the comment itself, and the
game’s rating (see figure 2.4):
{
"gameId": 1234,
"comment": "This game is awesome",
"rate": 3
}
Figure 2.4. Collection of comments
An overall schema of the comments service is shown in figure 2.5. On the server layer, it
runs on the Apache TomEE application server (http://tomee.apache.org); and for the
persistence layer, it uses the MongoDB NoSQL database for storing and retrieving
comments associated with games.
Figure 2.5. Comments service overview
Apache TomEE
Apache TomEE (http://tomee.apache.org), pronounced “Tommy,” is an all­Apache Java
EE 6 Web Profile–certified and EE 7–enabled stack where Apache Tomcat is top dog.
Apache TomEE is assembled from a vanilla Apache Tomcat zip file. Starting with
Apache Tomcat, TomEE adds its JARs and zips up the rest. The result is Tomcat with
added EE features—hence, the name TomEE.
2.3.3. The video service
Build the video service using the following code:
cd video
./gradlew build ­x test
The video service is a Spring Boot application that’s responsible for retrieving the three
most prominent videos related to a given game. Notice that this feature isn’t provided
by IGDB; it’s something you’ll add to the portal to make it more attractive to end users.
Obviously, this service isn’t going to reinvent the wheel by creating a new video­
sharing/­streaming site, so it uses YouTube to retrieve videos.
YouTube
YouTube is a global video­sharing website. You can add YouTube functionality to any
site and even search for content.
The YouTube Data API is the REST API that YouTube provides to users to connect to
its system and execute operations like uploading videos, modifying videos, and
searching for videos that match specific terms. See the book’s appendix for information
about how to use the YouTube Data API.
This service provides a single endpoint, which returns the links of the three most
prominent videos for the specified game.
This microservice has no persistence layer in the sense of long­lived data stored in the
system. For this microservice, a NoSQL in­memory database of key­value pairs is used
for caching search results from YouTube. When you’re caching distributed data where
optional durability is required, key­value databases are the best choice, because they fit
this requirement perfectly. With this approach, you save time, because an external
network hit is more expensive than an internal one. You also save on the hits quota
allotted by the YouTube Data API. In the video service, the key­value database used as a
caching system is the Redis database.
Redis
Redis is an in­memory data­structure store that can be used as a database, cache
system, or message broker. It supports data structures such as strings, hashes, lists,
sets, sorted sets with range queries, bitmaps, HyperLogLogs, and geospatial indexes
with radius queries.
Redis offers clustering capabilities, master­slave replication, and transactions, with
extremely good performance when not persisting data.
The Redis structure used for this microservice is a list. This basic structure holds a list
of string values for a given key with an optional TTL. In this case, the key is the game
ID, and the value of each element of the list is a URL of the video associated with the
game. As you can see in the schema shown in figure 2.6, the Redis structure stores a
game ID and a list of three YouTube URLs.
Spring Boot
Spring Boot (http://projects.spring.io/spring­boot) makes it easy to create standalone,
production­grade, Spring­based applications that you can “just run.” It follows the
uber(fat)­JAR approach by packaging an application into a single JAR file, which
contains the runtime (embedded server plus application) and a Main class to run it. It
integrates well with other products in the Spring ecosystem, like Spring Data and
Spring Security.
Figure 2.6. Video URLs cached in Redis
An overall schema of this service is shown in figure 2.7. You can see that the video
service is a Spring Boot application, and the cache layer it uses is Redis. The service
connects to the external site (youtube.com) to get video links for a specific game.
Figure 2.7. Video service
2.3.4. The aggregator service
Build and package the aggregator service using the following code:
cd aggregator
./gradlew war ­x test
This service is an EE 7 application that’s responsible for creating calls to the game and
comments services, merging the results of both calls into a single document, and
returning this document to the caller. This service provides three endpoints:
One for adding a comment and a game rating
A second that returns all the games that have a specified name
A third that returns all the data related to a specified game, all user comments and
ratings, and the three most important videos for the game
The overall schema of the aggregator service is shown in figure 2.8. It has no persistence
layer. The service runs inside the Apache Tomcat server and connects to all other
services.
Apache Tomcat
The Apache Tomcat server is an open source implementation of the Java Servlet,
JavaServer Pages, Java Expression Language, and Java WebSocket technologies.
Figure 2.8. Game aggregator service relations to other services
2.3.5. Overall architecture
2.3.5. Overall architecture
In summary, the Gamer app is made up of three services. Each of these services is
deployed in a different platform, from the light application server Apache TomEE to a
WildFly Swarm uber­JAR. Two different kinds of database engines are used for the
persistence layer: H2, a traditional SQL database, and MongoDB, which belongs to the
family of NoSQL databases.
This is a broad range of technologies. We chose to use these various technologies
specifically to broaden the scope of this book for the purposes of illustration. In the real
world, your applications are likely to be founded on technologies that are more similar
to each other. But, as mentioned previously, it’s not uncommon for different teams to
work on different microservices.
The overall schema of the Gamer app can be seen in the architecture diagram in figure
2.9. It’s important to note in the schema diagram how all the pieces are connected to
compose a fully functional, microservice­based application.
Figure 2.9. Architecture diagram of our project
2.4. APPLICATION DESIGN PATTERNS
In previous sections, you’ve read about the Gamer app from a high­level perspective,
and we’ve been paying a lot of attention to the requirements of the application from a
business perspective. In the following sections, we’ll dig down into the technical side of
the application.
2.4.1. Anatomy
The Gamer app follows the microservices architecture by applying the Single
Responsibility Principle (SRP) at an architectural level, making each service
independent in terms of deployment, technology, and language. In summary, each
microservice is structured following the schema shown in figure 2.10. Let’s see how each
piece is implemented in the Gamer app.
Figure 2.10. Detailed microservice structure
The resource component
The resource component is a thin layer of the application that acts as a mapper between
incoming messages (typically JSON documents) and the business logic in the domain
component. It also provides a response in accordance with the outcome produced by
the business logic, using the desired protocol.
In Java EE, this component is typically implemented using the Java API for RESTful
Web Services (JAX­RS), which provides support for creating web services following the
REST architectural pattern. An example of a resource component is coded in the
comments service
(code/comments/src/main/java/book/comments/boundary/CommentsResource.java).
Listing 2.1. Resource component
@Path("/comments") 1
@Singleton
@Lock(LockType.READ)
public class CommentsResource {
@Inject
private Comments comments;
@Inject
private DocumentToJsonObject transformer;
@GET 2
@Path("/{gameId}")
@Produces(MediaType.APPLICATION_JSON) 3
public Response getCommentsOfGivenGame(@PathParam("gameId")
final Integer
gameId) { 4
final Optional<Document>; commentsAndRating = comments
.getCommentsAndRating(gameId);
final JsonObject json = transformer.transform
(commentsAndRating.orElse(new Document()));
return Response.ok(json).build(); 5
}
}
1 Sets the relative path for a class or method
2 Indicates that the method services the HTTP GET request type
3 Sets the response MIME type
4 Binds the parameter to a path segment
5 Returns the content with the HTTP response code OK (200)
Request processing occurs by default in a synchronous fashion; this means a client
request is processed by a single container I/O thread from start to finish. This blocking
approach is fine for business logic that takes only a short time to execute.
But for long­running tasks, the container thread will remain occupied until the task has
been completed. This can have a significant impact on the server’s throughput, because
new connections can remain blocked longer than expected while waiting for the backlog
queue to be processed.
To resolve this problem, JAX­RS has an asynchronous model. This enables the
container thread to be released to accept a new connection before the client connection
is closed. The lengthy task runs in another thread, and the container I/O thread can be
used by another connection that’s waiting in the backlog queue.
An example of an asynchronous resource component is coded in the game service
(code/game/src/main/java/book/games/boundary/GamesResource.java), because
connections to external resources can take a considerable amount of time to complete.
Listing 2.2. Asynchronous resource component
@Path("/")
@javax.ejb.Singleton 1
@Lock(LockType.READ)
public class GamesResource {
@Inject
GamesService gamesService;
@Inject 2
ExecutorServiceProducer managedExecutorService;
@GET
@Produces(MediaType.APPLICATION_JSON)
@javax.ejb.Asynchronous 3
public void searchGames(@Suspended final AsyncResponse
response, 4
@NotNull @QueryParam("query") final
String query) {
response.setTimeoutHandler(asyncResponse ­>; asyncResponse
.resume(Response.status(Response.Status
.SERVICE_UNAVAILABLE).entity("TIME OUT !")
.build()));
response.setTimeout(15, TimeUnit.SECONDS);
managedExecutorService.getManagedExecutorService().submit(
() ­>; { 5
try {
final Collector<JsonObject, ?, JsonArrayBuilder>;
jsonCollector = Collector.of
(Json::createArrayBuilder,
JsonArrayBuilder::add, (left,
right) ­>; {
left.add(right);
return left;
});
final List<SearchResult>; searchResults =
gamesService.searchGames(query);
final JsonArrayBuilder mappedGames = searchResults
.stream().map(SearchResult::convertToJson)
.collect(jsonCollector);
final Response.ResponseBuilder ok = Response.ok
(mappedGames.build());
response.resume(ok.build()); 6
} catch (final Throwable e) {
response.resume(e); 7
}
});
}
}
1 Resource is marked as Singleton EJB so the endpoint becomes
transactional
2 Injects an executor service provided by the container
3 Designates a method as asynchronous. Valid only if it’s an EJB.
4 Instructs the JAX­RS runtime that this method is asynchronous and
injects an AsyncResponse
5 Executes logic in a different thread
6 When the result is ready, the connection is resumed.
7 In case of an error, communication should also be resumed.
For Spring applications, a resource is implemented using the Spring Web model­view­
controller (MVC) framework. This framework is built around the
DispatcherServlet class and dispatches requests to configured handlers for
executing business logic.
An example of a resource written for the Spring Web MVC framework is coded in the
video service (code/video/src/main/java/book/video/boundary/VideosResource.java).
Listing 2.3. Spring resource
package book.video.boundary;
import book.video.controller.VideoServiceController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@CrossOrigin(origins = {"http://localhost:8080",
"http://localhost:8181", "http://localhost:8282",
"http://localhost:8383"})
@RestController 1
public class VideosResource {
@Autowired 2
VideoServiceController videoServiceController;
@RequestMapping(value = "/", produces = "application/json") 3
public ResponseEntity<List<String>;>; getVideos(
@RequestParam ("videoId") final long videoId,
@RequestParam("gameName") final String gameName) {
final List<String>; linksFromGame = videoServiceController
.getLinksFromGame(Long.toString(videoId), gameName);
return ResponseEntity.ok(linksFromGame);
}
}
1 The resource is marked as a Spring Rest controller.
2 Injects video­service logic
3 Configures the endpoint method
Domain model
A domain model is a representation or abstraction of real­world concepts belonging to
the domain that need to be modeled in software. Each object of the domain
incorporates both the data and the behavior of the object.
In Java EE and Spring applications, if the domain is to be persisted to a SQL database,
then the domain is annotated with Java Persistence API (JPA) annotations. We’ll
discuss JPA in depth in chapters 4 and 5 .
An example is found in the game service
(code/game/src/main/java/book/games/entity/Game.java), where the domain model
is Game.
Listing 2.4. Domain model
@Entity
public class Game implements Serializable {
@Id
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Version
@Column(name = "version")
private int version;
@Column 1
private String title;
@Column
private String cover;
@ElementCollection
@CollectionTable(name = "ReleaseDate", joinColumns =
@JoinColumn(name = "OwnerId"))
private List<ReleaseDate>; releaseDates = new ArrayList<>;();
@ElementCollection
@CollectionTable(name = "Publisher", joinColumns = @JoinColumn
(name = "OwnerId"))
private List<String>; publishers = new ArrayList<>;();
@ElementCollection
@CollectionTable(name = "Developer", joinColumns = @JoinColumn
(name = "OwnerId"))
private List<String>; developers = new ArrayList<>;();
public JsonObject convertToJson() { 2
final JsonArrayBuilder developers = Json.createArrayBuilder();
this.getDevelopers().forEach(developers::add);
final JsonArrayBuilder publishers = Json.createArrayBuilder();
this.getPublishers().forEach(publishers::add);
final JsonArrayBuilder releaseDates = Json
.createArrayBuilder();
this.getReleaseDates().forEach(releaseDate ­>; {
final String platform = releaseDate.getPlatformName();
final String date = releaseDate.getReleaseDate().format
(DateTimeFormatter.ISO_DATE);
releaseDates.add(Json.createObjectBuilder().add
("platform", platform).add("release_date", date));
});
return Json.createObjectBuilder().add("id", this.getId())
.add("title", this.getTitle()).add("cover", this
.getCover()).add("developers", developers)
.add("publishers", publishers).add("release_dates",
releaseDates).build();
}
}
1 Domain objects have fields that describe their properties in the
system.
2 Object­manipulation methods should reside within the object.
Service layer
The services in the service layer are responsible for coordinating the various domain
activities and interactions with other subsystems. For example, these services handle
database interactions through the persistence component and call external services
through the remote­resource component.
In Java EE and Spring, this layer is usually implemented as a simple Java class, which
is annotated in order to be eligible for injection either by context dependency injection
(CDI), or autowiring in Spring components. Services should be injectable in any
element that makes up the microservice.
One example of a Java EE service can be found in the game service
(code/game/src/main/java/book/games/control/GamesService.java). This service is
responsible for checking if a game is cached in the Gamer local database, or if it must
first be retrieved from the IGDB API.
Listing 2.5. Java EE service
@Dependent 1
public class GamesService {
@EJB 2
Games games;
@EJB
IgdbGateway igdbGateway;
public Game searchGameById(final long gameId) throws IOException {
final Optional<Game>; foundGame = games.findGameById(gameId); 3
if (isGameInSiteDatabase(foundGame)) {
return foundGame.get();
} else {
final JsonArray jsonByGameId = igdbGateway
.searchGameById(gameId); 4
final Game game = Game.fromJson(jsonByGameId);
games.create(game);
return game;
}
}
}
1 Sets this class eligible for a CDI container as Dependent scoped
2 Other elements can be injected in a service.
3 Finds a game in the database
4 If the game isn’t found, gets it from IGDB
A Spring service example can be found in the video service
(code/video/src/main/java/book/video/boundary/YouTubeVideos.java).
Listing 2.6. Spring service
package book.video.boundary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class YouTubeVideos {
@Autowired
StringRedisTemplate redisTemplate;
public void createYouTubeLinks(final String gameId, final
List<String>; youtubeLinks) {
final ListOperations<String, String>;
stringStringListOperations = redisTemplate
.opsForList();
stringStringListOperations.leftPushAll(gameId, youtubeLinks);
}
public boolean isGameInserted(final String gameId) {
final ListOperations<String, String>;
stringStringListOperations = redisTemplate
.opsForList();
return stringStringListOperations.size(gameId) >; 0;
}
public List<String>; getYouTubeLinks(final String gameId) {
final ListOperations<String, String>;
stringStringListOperations = redisTemplate
.opsForList();
final Long size = stringStringListOperations.size(gameId);
return stringStringListOperations.range(gameId, 0, size);
}
}
Repositories
Repositories act on collections of domain entities and generally act as entry points or
bridges to the persistence­component backend.
Tip
If you’re only going to manage a single entity, we don’t recommend adding a repository
layer, because it would add unnecessary overhead. There’s also no need to pass objects
through layers that never interact with them. For educational purposes, we’ve
implemented a simple repository layer that demonstrates how to best test the class in a
real­world scenario.
When using a SQL database over JPA in a Java EE container, you should use Enterprise
Java Beans (EJBs), because they provide transactional awareness, concurrency
management, and security out of the box.
An example repository layer can be found in the game service
(code/game/src/main/java/book/games/boundary/Games.java).
Listing 2.7. Repository layer
@Stateless 1
public class Games {
@PersistenceContext 2
EntityManager em;
public Long create(final Game request) {
final Game game = em.merge(request); 3
return game.getId();
}
public Optional<Game>; findGameById(final Long gameId) {
Optional<Game>; g = Optional.ofNullable(em.find(Game.class,
gameId));
if (g.isPresent()) {
Game game = g.get();
game.getReleaseDates().size();
game.getPublishers().size();
game.getDevelopers().size();
em.detach(game);
}
return g;
}
}
1 EJBs ensure that classes are transaction aware by default.
2 Injects the EntityManager for database operations
3 Creates a new game
When you use Spring, repositories are usually written to use the Spring Data project.
This provides a familiar, consistent, Spring­based programming model for data access
to relational and non­relational data stores, as well as to map­reduce frameworks and
cloud­based data services. An example of a repository utilizing Spring Data can be
found in the video service code for accessing Redis.
Data mappers and object-relational mapping
Just about all microservices need to persist some kind of data to persistent storage. In
Java EE, when the persistence backend is a SQL database, the JPA specification is used
through an object­relational mapping (ORM) tool. ORM is a technique for converting
classes of object­oriented programming (OOP) languages into relational tables of
relational database systems (RDBSs).
Tip
Some vendors also offer object mapping to NoSQL databases, but this feature isn’t in
the specification.
A JPA data­mapping example that demonstrates this capability can be seen in the game
service (code/game/src/main/java/book/games/entity/Game.java).
Listing 2.8. Data mapping
@Entity
public class Game implements Serializable {
@Id
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Version
@Column(name = "version")
private int version;
@Column 1
private String title;
@Column
private String cover;
@ElementCollection
@CollectionTable(name = "ReleaseDate", joinColumns =
@JoinColumn(name = "OwnerId"))
private List<ReleaseDate>; releaseDates = new ArrayList<>;();
@ElementCollection
@CollectionTable(name = "Publisher", joinColumns = @JoinColumn
(name = "OwnerId"))
private List<String>; publishers = new ArrayList<>;();
@ElementCollection
@CollectionTable(name = "Developer", joinColumns = @JoinColumn
(name = "OwnerId"))
private List<String>; developers = new ArrayList<>;();
}
1 Object properties are mapped to relational table elements.
Gateways and the HTTP client
When a service collaborates with one or more microservices, logic must be
implemented to communicate with these external services. A gateway encapsulates all
the logic for connecting to a remote service and takes care of the underlying protocol
and marshalling/unmarshalling objects to and from domain objects. REST
architectures generally use the RESTful­web­services approach, so a gateway will more
often than not use an HTTP client to connect to the external service. In Java EE, the
JAX­RS specification provides client classes for consuming RESTful web services.
Spring provides a simple but powerful class called RestTemplate, which provides
methods for consuming other REST services. An example of a gateway that
communicates with another microservice can be found in the aggregator service
(code/aggregator/src/main/java/book/aggr/GamesGateway.java).
Listing 2.9. Gateway
Listing 2.9. Gateway
public class GamesGateway {
private final Client client;
private final WebTarget games;
private final String gamesHost;
public GamesGateway() {
this.client = ClientBuilder.newClient();
this.gamesHost = Optional.ofNullable(System.getenv
("GAMES_SERVICE_URL")).orElse(Optional.ofNullable
(System.getProperty("GAMES_SERVICE_URL")).orElse
("http://localhost:8181/"));
this.games = this.client.target(gamesHost); 1
}
public Future<JsonObject>; getGameFromGamesService(final long
gameId) {
return this.games.path("{gameId}").resolveTemplate
("gameId", gameId) 2
.register(JsonStructureBodyReader.class) 3
.request(MediaType.APPLICATION_JSON).async() 4
.get(JsonObject.class);
}
}
1 Creates a client connection to a given server
2 Defines the endpoint URL
3 Registers the unmarshaller
4 Usually, aggregators want to execute calls in asynchronous mode.
In this section, we’ve introduced you to the layers of a microservice. Let’s now see how
to bring each of these elements into the Java space.
2.4.2. ECB pattern
Each microservice developed for the Gamer app follows the entity control boundary
(ECB) pattern. ECB is a variant of the well­known MVC pattern, but unlike MVC, it’s
responsible not only for dealing with user interfaces, but also for applications (in our
case, microservices) that don’t have a UI.
The ECB pattern is composed of three elements (or key perspectives): entity, control,
and boundary. Each element of a microservice can be assembled into one of these three
perspectives:
Entity—An object that represents a domain model. It primarily contains the data
(attributes) required by the domain, but also performs behavior operations related
to the entity, such as validating data and performing business operations.
Control—An object that acts as the mediator between boundaries and entities. It
manages the end­to­end behavior of a scenario.
Boundary—An object that lies on the border of the system. Some boundary objects
might be responsible for the frontend of the system: for example, REST endpoints.
Others might be responsible for the backend, managing communications to external
elements such as databases or other services, for example.
Figure 2.11 shows how these elements fit together.
Figure 2.11. ECB pattern
The three elements can have certain appropriate interactions; others should not occur.
The relationships between the entity, control, and boundary objects can be summarized
as follows:
An element can communicate with other elements of the same kind.
A control can communicate with entity and boundary elements.
Boundary and entity elements shouldn’t communicate directly.
Table 2.8 illustrates these relations.
Table 2.8. Communication between entity, control, and boundary objects
Entity Boundary Control
Entity X X
Boundary X X
Random documents with unrelated
content Scribd suggests to you:
179 «¡Padre Júpiter! Haz que le caiga la suerte á Ayax, al hijo de
Tideo, ó al mismo rey de Micenas, rica en oro.»
181 Así decían. Néstor, caballero gerenio, meneaba el casco,
hasta que por fin saltó la tarja que ellos querían, la de Ayax. Un
heraldo llevóla por el concurso y, empezando por la derecha, la
enseñaba á los próceres aqueos, quienes, al no reconocerla,
negaban que fuese la suya; pero cuando llegó al que la había
marcado y echado en el casco, al ilustre Ayax, éste tendió la mano, y
aquel se detuvo y le entregó la contraseña. El héroe la reconoció,
con gran júbilo de su corazón, y tirándola al suelo, á sus pies,
exclamó:
191 «¡Oh amigos! Mi tarja es, y me alegro en el alma porque
espero vencer al divino Héctor. ¡Ea! Mientras visto la bélica
armadura, orad al soberano Jove Saturnio, mentalmente, para que
no lo oigan los teucros; ó en alta voz, pues á nadie tememos. No
habrá quien, valiéndose de la fuerza ó de la astucia, me ponga en
fuga contra mi voluntad; porque no creo que naciera y me criara en
Salamina, tan inhábil para la lucha.»
200 Tales fueron sus palabras. Ellos oraron al soberano Jove
Saturnio, y algunos dijeron mirando al anchuroso cielo:
202 «¡Padre Júpiter, que reinas desde el Ida, gloriosísimo,
máximo! Concédele á Ayax la victoria y un brillante triunfo; y si amas
también á Héctor y por él te interesas, dales á entrambos igual
fuerza y gloria.»
206 Así hablaban. Púsose Ayax la armadura de luciente bronce; y
vestidas las armas, marchó tan animoso como el terrible Marte
cuando se encamina al combate de los hombres á quienes el
Saturnio hace venir á las manos por una roedora discordia. Tan
terrible se levantó Ayax, antemural de los aqueos, que sonreía con
torva faz, andaba á paso largo y blandía enorme lanza. Los argivos
se regocijaron grandemente, así que le vieron, y un violento temblor
se apoderó de los teucros; al mismo Héctor palpitóle el corazón en el
pecho; pero ya no podía manifestar temor ni retirarse á su ejército,
porque de él había partido la provocación. Ayax se le acercó con su
escudo como una torre, broncíneo, de siete pieles de buey, que en
otro tiempo le hiciera Tiquio, el cual habitaba en Hila y era el mejor
É
de los curtidores. Éste formó el versátil escudo con siete pieles de
corpulentos bueyes y puso encima, como octava capa, una lámina
de bronce. Ayax Telamonio paróse, con la rodela al pecho, muy
cerca de Héctor; y amenazándole, dijo:
226 «¡Héctor! Ahora sabrás claramente, de solo á solo, cuáles
adalides pueden presentar los dánaos, aun prescindiendo de Aquiles
que destruye los escuadrones y tiene el ánimo de un león. Mas el
héroe, enojado con Agamenón, pastor de hombres, permanece en
las corvas naves, que atraviesan el ponto, y somos muchos los
capaces de pelear contigo. Pero empiece ya la lucha y el combate.»
233 Respondióle el gran Héctor, de tremolante casco: «¡Ayax
Telamonio, de jovial linaje, príncipe de hombres! No me tientes cual
si fuera un débil niño ó una mujer que no conoce las cosas de la
guerra. Versado estoy en los combates y en las matanzas de
hombres; sé mover á diestro y á siniestro la seca piel de buey que
llevo para luchar denodadamente, sé lanzarme á la pelea cuando en
prestos carros se batalla, y sé deleitar á Marte en el cruel estadio de
la guerra. Pero á ti, siendo cual eres, no quiero herirte con alevosía,
sino cara á cara, si conseguirlo puedo.»
Ayax fué al encuentro de Héctor, con su escudo como una torre
(Canto VII, verso 219.)
244 Dijo, y blandiendo la enorme lanza, arrojóla y atravesó el
bronce que cubría como octava capa el gran escudo de Ayax,
formado por siete boyunos cueros: la indomable punta horadó seis
de éstos y en el séptimo quedó detenida. Ayax, descendiente de
Júpiter, tiró á su vez un bote en el escudo liso del Priámida, y el
asta, pasando por la tersa rodela, se hundió en la labrada coraza y
rasgó la túnica sobre el ijar; inclinóse el héroe, y evitó la negra
muerte. Y arrancando ambos las luengas lanzas de los escudos,
acometiéronse como carniceros leones ó puercos monteses cuya
fuerza es inmensa. El Priámida hirió con la lanza el centro del escudo
de Ayax, y el bronce no pudo romperlo porque la punta se torció.
Ayax, arremetiendo, clavó la suya en la rodela de aquél, é hizo
vacilar al héroe cuando se disponía para el ataque; la punta abrióse
camino hasta el cuello de Héctor, y en seguida brotó la negra
sangre. Mas no por esto cesó de combatir Héctor, de tremolante
casco, sino que, volviéndose, cogió con su robusta mano un
pedrejón negro y erizado de puntas que había en el campo; lo tiró,
acertó á dar en el bollón central del gran escudo de Ayax, de siete
boyunas pieles, é hizo resonar el bronce de la rodela. Ayax entonces,
tomando una piedra mucho mayor, la despidió haciéndola voltear
con una fuerza inmensa. La piedra torció el borde inferior del
hectóreo escudo, cual pudiera hacerlo una muela de molino, y
chocando con las rodillas de Héctor le tumbó de espaldas, asido á la
rodela; pero Apolo en seguida le puso en pie. Y ya se hubieran
atacado de cerca con las espadas, si no hubiesen acudido dos
heraldos, mensajeros de Júpiter y de los hombres, que llegaron
respectivamente del campo de los teucros y del de los aqueos, de
broncíneas lorigas: Taltibio é Ideo, prudentes ambos. Éstos
interpusieron sus cetros entre los campeones, é Ideo, hábil en dar
sabios consejos, pronunció estas palabras:
279 «¡Hijos queridos! No peleéis ni combatáis más; á entrambos
os ama Júpiter, que amontona las nubes, y ambos sois belicosos.
Esto lo sabemos todos. Pero la noche comienza ya, y será bueno
obedecerla.»
283 Respondióle Ayax Telamonio: «¡Ideo! Ordenad á Héctor que
lo disponga, pues fué él quien retó á los más valientes. Sea el
primero en desistir; que yo obedeceré, si él lo hiciere.»
287 Díjole el gran Héctor, de tremolante casco: «¡Ayax! Puesto
que los dioses te han dado corpulencia, valor y cordura, y en el
manejo de la lanza descuellas entre los aqueos, suspendamos por
hoy el combate y la lucha, y otro día volveremos á pelear hasta que
una deidad nos separe, después de otorgar la victoria á quien
quisiere. La noche comienza ya, y será bueno obedecerla. Así tú
regocijarás, en las naves, á todos los aqueos y especialmente á tus
amigos y compañeros; y yo alegraré, en la gran ciudad del rey
Príamo, á los troyanos y á las troyanas, de rozagantes peplos, que
habrán ido á los sagrados templos á orar por mí. ¡Ea! Hagámonos
magníficos regalos, para que digan aqueos y teucros: Combatieron
con roedor encono, y se separaron por la amistad unidos.»
303 Cuando esto hubo dicho, entregó á Ayax una espada
guarnecida con argénteos clavos, ofreciéndosela con la vaina y el
bien cortado ceñidor; y Ayax regaló á Héctor un vistoso tahalí teñido
de púrpura. Separáronse luego, volviendo el uno á las tropas aqueas
y el otro al ejército de los teucros. Éstos se alegraron al ver á Héctor
vivo, y que regresaba incólume, libre de la fuerza y de las invictas
manos de Ayax, cuando ya desesperaban de que se salvara; y le
acompañaron á la ciudad. Por su parte, los aqueos, de hermosas
grebas, llevaron á Ayax, ufano de la victoria, á la tienda del divino
Agamenón.
313 Así que estuvieron en ella, Agamenón Atrida, rey de
hombres, sacrificó al prepotente Saturnio un buey de cinco años.
Tan pronto como lo hubieron desollado y preparado, lo
descuartizaron hábilmente y cogiendo con pinchos los pedazos, los
asaron con el cuidado debido y los retiraron del fuego. Terminada la
faena y dispuesto el festín, comieron sin que nadie careciese de su
respectiva porción; y el poderoso héroe Agamenón Atrida obsequió á
Ayax con el ancho lomo. Cuando hubieron satisfecho el deseo de
comer y de beber, el anciano Néstor, cuya opinión era considerada
siempre como la mejor, comenzó á darles un consejo. Y
arengándolos con benevolencia, así les dijo:
327 «¡Atrida y demás príncipes de los aqueos todos! Ya que han
muerto tantos aquivos, de larga cabellera, cuya sangre esparció el
cruel Marte por la ribera del Escamandro de límpida corriente y
cuyas almas descendieron al Orco, conviene que suspendas los
combates; y mañana, reunidos todos al comenzar del día, traeremos
los cadáveres en carros tirados por bueyes y mulos, y los
quemaremos cerca de los bajeles para llevar sus cenizas á los hijos
de los difuntos cuando regresemos á la patria. Erijamos luego con
tierra de la llanura, amontonada en torno de la pira, un túmulo
común; edifiquemos á partir del mismo una muralla con altas torres
que sea un reparo para las naves y para nosotros mismos; dejemos
puertas, que se cierren con bien ajustadas tablas, para que pasen
los carros, y cavemos al pie del muro un profundo foso, que detenga
á los hombres y á los caballos si algún día no podemos resistir la
acometida de los altivos teucros.»
344 Así habló, y los demás reyes aplaudieron. Reuniéronse los
teucros en la acrópolis de Ilión, cerca del palacio de Príamo; y la
junta fué agitada y turbulenta. El prudente Antenor comenzó á
arengarles de esta manera:
348 «¡Oídme, troyanos, dárdanos y aliados, y os manifestaré lo
que en el pecho mi corazón me dicta! Ea, restituyamos la argiva
Helena con sus riquezas y que los Atridas se la lleven. Ahora
combatimos después de quebrar la fe ofrecida en los juramentos, y
no espero que alcancemos éxito alguno mientras no hagamos lo que
propongo.»
354 Dijo, y se sentó. Levantóse el divino Alejandro, esposo de
Helena, la de hermosa cabellera, y dirigiéndose á aquél pronunció
estas aladas palabras:
357 «¡Antenor! No me place lo que propones, y podías haber
pensado algo mejor. Si realmente hablas con seriedad, los mismos
dioses te han hecho perder el juicio. Y á los troyanos, domadores de
caballos, les diré lo siguiente: Paladinamente lo declaro, no
devolveré la esposa; pero sí quiero dar cuantas riquezas traje de
Argos y aun otras que añadiré de mi casa.»
365 Dijo, y se sentó. Levantóse Príamo Dardánida, consejero
igual á los dioses, y les arengó con benevolencia diciendo:
368 «¡Oídme, troyanos, dárdanos y aliados, y os manifestaré lo
que en el pecho mi corazón me dicta! Cenad en la ciudad, como
siempre; acordaos de la guardia, y vigilad todos; al romper el alba
vaya Ideo á las cóncavas naves, anuncie á los Atridas, Agamenón y
Menelao, la proposición de Alejandro, por quien se suscitó la
contienda, y hágales esta prudente consulta: Si quieren que se
suspenda el horrísono combate para quemar los cadáveres, y luego
volveremos á pelear hasta que una deidad nos separe y otorgue la
victoria á quien le plazca.»
379 De esta suerte habló; ellos le escucharon y obedecieron,
tomando la cena en el campo sin romper las filas; y apenas comenzó
á alborear, encaminóse Ideo á las cóncavas naves y halló á los
dánaos, ministros de Marte, reunidos en junta cerca del bajel de
Agamenón. El heraldo de voz sonora, puesto en medio, les dijo:
385 «¡Atrida y demás príncipes de los aqueos todos! Mándanme
Príamo y los ilustres troyanos que os participe, y ojalá os fuera
acepta y grata, la proposición de Alejandro, por quien se suscitó la
contienda. Ofrece dar cuantas riquezas trajo á Ilión en las cóncavas
naves—¡así hubiese perecido antes!—y aun añadir otras de su casa;
pero se niega á devolver la legítima esposa del glorioso Menelao, á
pesar de que los troyanos se lo aconsejan. Me han ordenado
también que os haga esta consulta: Si queréis que se suspenda el
horrísono combate para quemar los cadáveres, y luego volveremos á
pelear hasta que una deidad nos separe y otorgue la victoria á quien
le plazca.»
398 Así habló. Todos enmudecieron y quedaron silenciosos. Pero
al fin Diomedes, valiente en la pelea, dijo:
400 «No se acepten ni las riquezas de Alejandro, ni á Helena
tampoco; pues es evidente, hasta para el más simple, que la ruina
pende sobre los troyanos.»
403 Así se expresó; y todos los aqueos aplaudieron, admirados
del discurso de Diomedes, domador de caballos. Y el rey Agamenón
dijo entonces á Ideo:
406 «¡Ideo! Tú mismo oyes las palabras con que te responden
los aqueos; ellas son de mi agrado. En cuanto á los cadáveres, no
me opongo á que sean quemados, pues ha de ahorrarse toda
dilación para satisfacer prontamente á los que murieron, entregando
sus cuerpos á las llamas. Júpiter tonante, esposo de Juno, reciba el
juramento.»
412 Dicho esto, alzó el cetro á todos los dioses; é Ideo regresó á
la sagrada Troya, donde le esperaban, reunidos en junta, troyanos y
dárdanos. El heraldo, puesto en medio, dijo la respuesta. En seguida
dispusiéronse unos á recoger los cadáveres, y otros á ir por leña. Á
su vez, los argivos salieron de las naves de numerosos bancos; unos,
para recoger los cadáveres, y otros, para cortar leña.
421 Ya el sol hería con sus rayos los campos, subiendo al cielo
desde la plácida corriente del profundo Océano, cuando aqueos y
teucros se mezclaron unos con otros en la llanura. Difícil era
reconocer á cada varón; pero lavaban con agua las manchas de
sangre de los cadáveres y, derramando ardientes lágrimas, los
subían á los carros. El gran Príamo no permitía que los teucros
lloraran: éstos, en silencio y con el corazón afligido, hacinaron los
cadáveres sobre la pira, los quemaron y volvieron á la sacra Ilión.
Del mismo modo, los aqueos, de hermosas grebas, hacinaron los
cadáveres sobre la pira, los quemaron y volvieron á las cóncavas
naves.
433 Cuando aún no despuntaba la aurora, pero ya la luz del alba
aparecía, un grupo escogido de aqueos se reunió en torno de la pira.
Erigieron con tierra de la llanura un túmulo común; construyeron á
partir del mismo una muralla con altas torres, que sirviese de reparo
á las naves y á ellos mismos; dejaron puertas, que se cerraban con
bien ajustadas tablas, para que pudieran pasarlos carros, y cavaron
al pie del muro un gran foso profundo y ancho que defendieron con
estacas. De tal suerte trabajaban los aqueos, de larga cabellera.
443 Los dioses, sentados á la vera de Júpiter fulminador,
contemplaban la grande obra de los aqueos, de broncíneas lorigas; y
Neptuno, que sacude la tierra, empezó á decirles:
446 «¡Padre Júpiter! ¿Cuál de los mortales de la vasta tierra
consultará con los dioses sus pensamientos y proyectos? ¿No ves
que los aqueos, de larga cabellera, han construído delante de las
naves un muro con su foso, sin ofrecer á los dioses hecatombes
perfectas? La fama de este muro se extenderá tanto como la luz de
la aurora; y se echará en olvido el que labramos Febo Apolo y yo,
cuando con gran fatiga construímos la ciudad para el héroe
Laomedonte.»
454 Júpiter, que amontona las nubes, respondió indignado: «¡Oh
dioses! ¡Tú, prepotente batidor de la tierra, qué palabras proferiste!
Á un dios muy inferior en fuerza y ánimo podría asustarle tal
pensamiento; pero no á ti, cuya fama se extenderá tanto como la luz
de la aurora. Ea, cuando los aqueos, de larga cabellera, regresen en
las naves á su patria, derriba el muro, arrójalo entero al mar, y
enarena otra vez la espaciosa playa para que desaparezca la gran
muralla aquiva.»
464 Así éstos conversaban. Á puesta del sol los aqueos tenían la
obra acabada; inmolaron bueyes y se pusieron á cenar en las
respectivas tiendas, cuando arribaron, procedentes de Lemnos,
muchas naves cargadas de vino que enviaba Euneo, hijo de Hipsipile
y de Jasón, pastor de hombres. El hijo de Jasón mandaba
separadamente, para los Atridas Agamenón y Menelao, mil medidas
de vino. Los aqueos, de larga cabellera, acudieron á las naves;
compraron vino, unos con bronce, otros con luciente hierro, otros
con pieles, otros con vacas y otros con esclavos; y prepararon un
festín espléndido. Toda la noche los aquivos, de larga cabellera,
disfrutaron del banquete, y lo mismo hicieron en la ciudad los
troyanos y sus aliados. Toda la noche estuvo el próvido Júpiter
meditando cómo les causaría males, hasta que por fin tronó de un
modo horrible: el pálido temor se apoderó de todos, derramaron á
tierra el vino de las copas, y nadie se atrevió á beber sin que antes
hiciera libaciones al prepotente Saturnio. Después se acostaron y el
don del sueño recibieron.
Las Horas desuncen los corceles del carro en que iban Juno y Minerva
CANTO VIII
BATALLA INTERRUMPIDA
1 La Aurora, de azafranado velo, se esparcía por toda la tierra,
cuando Júpiter, que se complace en lanzar rayos, reunió la junta de
los dioses en la más alta de las muchas cumbres del Olimpo. Y así
les habló, mientras ellos atentamente le escuchaban:
5 «¡Oídme todos, dioses y diosas, para que os manifieste lo que
en el pecho mi corazón me dicta! Ninguno de vosotros, sea varón ó
hembra, se atreva á transgredir mi mandato; antes bien, asentid
todos, á fin de que cuanto antes lleve al cabo lo que me propongo.
El dios que intente separarse de los demás y socorrer á los teucros ó
á los dánaos, como yo le vea, volverá afrentosamente golpeado al
Olimpo; ó cogiéndole, lo arrojaré al tenebroso Tártaro, muy lejos, en
lo más profundo del báratro debajo de la tierra—sus puertas son de
hierro, y el umbral, de bronce, y su profundidad desde el Orco como
del cielo á la tierra—y conocerá en seguida cuánto aventaja mi poder
al de las demás deidades. Y si queréis, haced esta prueba, oh
dioses, para que os convenzáis. Suspended del cielo áurea cadena,
asíos todos, dioses y diosas, de la misma, y no os será posible
arrastrar del cielo á la tierra á Júpiter, árbitro supremo, por mucho
que os fatiguéis; mas si yo me resolviese á tirar de aquélla, os
levantaría con la tierra y el mar, ataría un cabo de la cadena en la
cumbre del Olimpo, y todo quedaría en el aire. Tan superior soy á los
dioses y á los hombres.»
28 Así habló; y todos callaron, asombrados de sus palabras,
pues fué mucha la vehemencia con que se expresara. Al fin,
Minerva, la diosa de los brillantes ojos, dijo:
31 «¡Padre nuestro, Saturnio, el más excelso de los soberanos!
Bien sabemos que es incontrastable tu poder; pero tenemos lástima
de los belicosos dánaos, que morirán, y se cumplirá su aciago
destino. Nos abstendremos de intervenir en el combate, si nos lo
mandas; pero sugeriremos á los argivos consejos saludables, á fin
de que no perezcan todos, víctimas de tu cólera.»
38 Sonriéndose, le contestó Júpiter, que amontona las nubes:
«Tranquilízate, Tritogenia, hija querida. No hablo con ánimo benigno,
pero contigo quiero ser complaciente.»
41 Esto dicho, unció los corceles de pies de bronce y áureas
crines, que volaban ligeros; vistió la dorada túnica, tomó el látigo de
oro y fina labor, y subió al carro. Picó á los caballos para que
arrancaran; y éstos, gozosos, emprendieron el vuelo entre la tierra y
el estrellado cielo. Pronto llegó al Ida, abundante en fuentes y
criador de fieras, al Gárgaro, donde tenía un bosque sagrado y un
perfumado altar; allí el padre de los hombres y de los dioses detuvo
los bridones, los desenganchó del carro y los cubrió de espesa
niebla. Sentóse luego en la cima, ufano de su gloria, y se puso á
contemplar la ciudad troyana y las naves aqueas.
53 Los aqueos, de larga cabellera, se desayunaron
apresuradamente en las tiendas, y en seguida tomaron las armas.
También los teucros se armaron dentro de la ciudad; y aunque eran
menos, estaban dispuestos á combatir, obligados por la cruel
necesidad de proteger á sus hijos y mujeres: abriéronse todas las
puertas, salió el ejército de infantes y de los que peleaban en carros,
y se produjo un gran tumulto.
60 Cuando los dos ejércitos llegaron á juntarse, chocaron entre
sí los escudos, las lanzas y el valor de los guerreros armados de
broncíneas corazas, y al aproximarse las abollonadas rodelas se
produjo un gran tumulto. Allí se oían simultáneamente los lamentos
de los moribundos y los gritos jactanciosos de los matadores, y la
tierra manaba sangre.
66 Al amanecer y mientras iba aumentando la luz del sagrado
día, los tiros alcanzaban por igual á unos y á otros, y los hombres
caían. Cuando el sol hubo recorrido la mitad del cielo, el padre Jove
tomó la balanza de oro, puso en ella dos suertes—la de los teucros,
domadores de caballos, y la de los aqueos, de broncíneas lorigas—
para saber á quiénes estaba reservada la dolorosa muerte; cogió por
el medio la balanza, la desplegó y tuvo más peso el día fatal de los
aqueos. La suerte de éstos bajó hasta llegar á la fértil tierra,
mientras la de los teucros subía al cielo. Júpiter, entonces, truena
fuerte desde el Ida y envía una ardiente centella á los aqueos,
quienes, al verla, se pasman, sobrecogidos de pálido temor; ya no
se atreven á permanecer en el campo ni Idomeneo, ni Agamenón, ni
los dos Ayaces, ministros de Marte; y sólo se queda Néstor gerenio,
protector de los aqueos, contra su voluntad, por tener malparado
uno de los corceles, al cual el divino Alejandro, esposo de Helena, la
de hermosa cabellera, flechara en lo alto de la cabeza, donde las
crines empiezan á crecer y las heridas son mortales. El caballo, al
sentir el dolor, se encabrita, y la flecha le penetra el cerebro; y
revolcándose para sacudir el bronce, espanta á los demás caballos.
Mientras el anciano se daba prisa á cortar con la espada las correas
del caído corcel, vienen á través de la muchedumbre los veloces
caballos de Héctor, tirando del carro en que iba tan audaz guerrero.
Y el anciano perdiera allí la vida, si al punto no lo hubiese advertido
Diomedes, valiente en la pelea; el cual, vociferando de un modo
horrible, dijo á Ulises:
93 «¡Laertíada, de jovial linaje! ¡Ulises, fecundo en recursos!
¿Adónde huyes, confundido con la turba y volviendo la espalda como
un cobarde? Que alguien no te clave la pica en el dorso, mientras
pones los pies en polvorosa. Pero aguarda y apartaremos del
anciano al feroz guerrero.»
97 Así dijo, y el paciente divino Ulises pasó sin oirle, corriendo
hacia las cóncavas naves de los aqueos. El hijo de Tideo, aunque
estaba solo, se abrió paso por las primeras filas; y deteniéndose
ante el carro del viejo Nelida, pronunció estas aladas palabras:
102 «¡Oh anciano! Los guerreros mozos te acosan y te hallas sin
fuerzas, abrumado por la molesta senectud; tu escudero tiene poco
vigor y tus caballos son tardos. Sube á mi carro para que veas
cuáles son los corceles de Tros que quité á Eneas, el que pone en
fuga á sus enemigos, y cómo saben lo mismo perseguir acá y allá de
la llanura, que huir ligeros. De los tuyos cuiden los servidores; y
nosotros dirijamos éstos hacia los teucros, domadores de caballos,
para que Héctor sepa con qué furia se mueve la lanza que mi mano
blande.»
112 Dijo; y Néstor, caballero gerenio, no desobedeció.
Encargáronse de sus yeguas los bravos escuderos Esténelo y
Eurimedonte valeroso; y habiendo subido ambos héroes al carro de
Diomedes, Néstor cogió las lustrosas riendas y avispó á los caballos,
y pronto se hallaron cerca de Héctor, que cerró con ellos. El hijo de
Tideo arrojóle un dardo, y si bien erró el tiro, hirió en el pecho cerca
de la tetilla á Eniopeo, hijo del animoso Tebeo, que, como auriga,
gobernaba las riendas: Eniopeo cayó del carro, cejaron los corceles y
allí terminaron la vida y el valor del guerrero. Hondo pesar sintió el
espíritu de Héctor por tal muerte; pero, aunque condolido del
compañero, dejóle en el suelo y buscó otro auriga que fuese osado.
Poco tiempo estuvieron los veloces caballos sin conductor, pues
Héctor encontróse con el ardido Arqueptólemo Ifítida, y haciéndole
subir, le puso las riendas en la mano.
130 Entonces gran estrago é irreparables males se hubieran
producido y los teucros habrían sido encerrados en Ilión como
corderos, si al punto no lo hubiese advertido el padre de los
hombres y de los dioses. Tronando de un modo espantoso, despidió
un ardiente rayo para que cayera en el suelo delante de los caballos
de Diomedes; el azufre encendido produjo una terrible llama; los
corceles, asustados, acurrucáronse debajo del carro; las lustrosas
riendas cayeron de las manos de Néstor, y éste, con miedo en el
corazón, dijo á Diomedes:
139 «¡Tidida! Tuerce la rienda á los solípedos caballos y
huyamos. ¿No conoces que la protección de Júpiter ya no te
acompaña? Hoy Jove Saturnio otorga á ése la victoria; otro día, si le
place, nos la dará á nosotros. Ningún hombre, por fuerte que sea,
puede impedir los propósitos de Júpiter, porque el dios es mucho
más poderoso.»
145 Respondióle Diomedes, valiente en la pelea: «Sí, anciano,
oportuno es cuanto acabas de decir, pero un terrible pesar me llega
al corazón y al alma. Quizás diga Héctor, arengando á los teucros: El
Tidida llegó á las naves, puesto en fuga por mi lanza. Así se jactará;
y entonces ábraseme la vasta tierra.»
151 Replicóle Néstor, caballero gerenio: «¡Ay de mí! ¡Qué dijiste,
hijo del belicoso Tideo! Si Héctor te llamare cobarde y débil, no le
creerán ni los troyanos, ni los dardanios, ni las mujeres de los
teucros magnánimos, escudados, cuyos esposos florecientes en el
polvo derribaste.»
157 Dichas estas palabras, volvió la rienda á los solípedos
caballos, y empezaron á huir por entre la turba. Los teucros y
Héctor, promoviendo inmenso alboroto, hacían llover sobre ellos
dañosos tiros. Y el gran Héctor, de tremolante casco, gritaba con voz
recia:
161 «¡Tidida! Los dánaos, de ágiles corceles, te cedían la
preferencia en el asiento y te obsequiaban con carne y copas de
vino; mas ahora te despreciarán, porque te has vuelto como una
mujer. Anda, tímida doncella; ya no escalarás nuestras torres,
venciéndome á mí, ni te llevarás nuestras mujeres en las naves,
porque antes te daré la muerte.»
167 Tal dijo. El Tidida estaba indeciso entre seguir huyendo ó
torcer la rienda á los corceles y volver á pelear. Tres veces se le
presentó la duda en la mente y en el corazón, y tres veces el próvido
Júpiter tronó desde los montes ideos para anunciar á los teucros que
suya sería en aquel combate la inconstante victoria. Y Héctor los
animaba, diciendo á voz en grito:
173 «¡Troyanos, licios, dárdanos que cuerpo á cuerpo combatís!
Sed hombres, amigos, y mostrad vuestro impetuoso valor. Conozco
que el Saturnio me concede, benévolo, la victoria y gloria inmensa y
envía la perdición á los dánaos; quienes, oh necios, construyeron
esos muros débiles y despreciables que no podrán contener mi
arrojo, pues los caballos salvarán fácilmente el cavado foso. Cuando
llegue á las cóncavas naves, acordaos de traerme el voraz fuego,
para que las incendie y mate junto á ellas á los argivos aturdidos por
el humo.»
184 Dijo, y exhortó á sus caballos con estas palabras: «¡Janto,
Podargo, Etón, divino Lampo! Ahora debéis pagarme el exquisito
cuidado con que Andrómaca, hija del magnánimo Eetión, os ofrecía
el regalado trigo y os mezclaba vinos para que pudieseis, bebiendo,
satisfacer vuestro apetito; antes que á mí, que me glorío de ser su
floreciente esposo. Seguid el alcance, esforzaos, para ver si nos
apoderamos del escudo de Néstor, cuya fama llega hasta el cielo por
ser de oro, sin exceptuar las abrazaderas, y le quitamos de los
hombros á Diomedes, domador de caballos, la labrada coraza que
Vulcano fabricara. Creo que si ambas cosas consiguiéramos, los
aqueos se embarcarían esta misma noche en las veleras naves.»
198 Así habló, vanagloriándose. La veneranda Juno, indignada,
se agitó en su trono, haciendo estremecer el espacioso Olimpo, y
dijo al gran dios Neptuno:
201 «¡Oh dioses! ¡Prepotente Neptuno que bates la tierra! ¿Tu
corazón no se compadece de los dánaos moribundos, que tantos y
tan lindos presentes te llevaban á Hélice y á Egas? Decídete á darles
la victoria. Si cuantos protegemos á los dánaos quisiéramos rechazar
á los teucros y contener al longividente Júpiter, éste se aburriría
sentado solo allá en el Ida.»
208 Respondióle muy indignado el poderoso dios que sacude la
tierra: «¿Qué palabras proferiste, audaz Juno? Yo no quisiera que los
demás dioses lucháramos con el Saturnio Jove, porque nos aventaja
mucho en poder.»
212 Así éstos conversaban. Cuanto espacio había desde los
bajeles al fosado muro, llenóse de carros y hombres escudados que
allí acorraló Héctor Priámida, igual al impetuoso Marte, cuando
Júpiter le dió gloria. Y el héroe hubiese pegado ardiente fuego á las
naves bien proporcionadas, de no haber sugerido la venerable Juno
á Agamenón que animara pronto á los aqueos. Fuése el Atrida hacia
las tiendas y las naves aqueas con el grande purpúreo manto en el
robusto brazo, y subió á la ingente nave negra de Ulises, que estaba
en el centro, para que le oyeran por ambos lados hasta las tiendas
de Ayax Telamonio y de Aquiles, los cuales habían puesto sus bajeles
en los extremos porque confiaban en su valor y en la fuerza de sus
brazos. Y con voz penetrante gritaba á los dánaos:
228 «¡Qué vergüenza, argivos, hombres sin dignidad, admirables
sólo por la figura! ¿Qué es de la jactancia con que nos gloriábamos
de ser valentísimos, y con que decíais presuntuosamente en
Lemnos, comiendo abundante carne de bueyes de erguida
cornamenta y bebiendo crateras de vino, que cada uno haría frente
en la batalla á ciento y á doscientos troyanos? Ahora ni con uno
podemos, con Héctor, que pronto pegará ardiente fuego á las naves.
¡Padre Júpiter! ¿Hiciste sufrir tamaña desgracia y privaste de una
gloria tan grande á algún otro de los prepotentes reyes? Cuando
vine, no pasé de largo en la nave de muchos bancos por ninguno de
tus bellos altares, sino que en todos quemé grasa y muslos de buey,
deseoso de asolar la bien murada Troya. Por tanto, oh Júpiter,
cúmpleme este voto: déjanos escapar y librarnos de este peligro, y
no permitas que los teucros maten á los argivos.»
245 Así se expresó. El padre, compadecido de verle derramar
lágrimas, le concedió que su pueblo se salvara y no pereciese; y en
seguida mandó un águila, la mejor de las aves agoreras, que tenía
en las garras el hijuelo de una veloz cierva y lo dejó caer al pie del
ara hermosa de Júpiter, donde los aqueos ofrecían sacrificios al dios,
como autor de los presagios todos. Cuando los argivos vieron que el
ave había sido enviada por Júpiter, arremetieron contra los teucros y
sólo en combatir pensaron.
253 Entonces ninguno de los dánaos, aunque eran muchos, pudo
gloriarse de haber revuelto sus veloces caballos para pasar el foso y
resistir el ataque, antes que el Tidida. Fué éste el primero que mató
á un guerrero teucro, á Agelao Fradmónida, que, subido en el carro,
emprendía la fuga: hundióle la pica en la espalda, entre los
hombros, y la punta salió por el pecho; Agelao cayó del carro y sus
armas resonaron.
261 Siguieron á Diomedes, los Atridas Agamenón y Menelao; los
Ayaces, revestidos de impetuoso valor; Idomeneo y su servidor
Meriones, igual al homicida Marte; Eurípilo, hijo ilustre de Evemón; y
en noveno lugar, Teucro, que, con el flexible arco en la mano, se
escondía detrás del escudo de Ayax Telamonio. Éste levantaba la
rodela; y Teucro, volviendo el rostro á todos lados, flechaba á un
troyano que caía mortalmente herido, y al momento tornaba á
refugiarse en Ayax (como un niño en su madre), quien le cubría otra
vez con el refulgente escudo.
273 ¿Cuál fué el primero, cuál el último de los que entonces
mató el eximio Teucro? Orsíloco el primero, Órmeno, Ofelestes,
Détor, Cromio, Licofontes igual á un dios, Amopaón Poliemónida y
Melanipo. Á tantos derribó sucesivamente al almo suelo. El rey de
hombres Agamenón se holgó de ver que Teucro destruía las falanges
troyanas, disparando el fuerte arco; y poniéndose á su lado, le dijo:
281 «¡Caro Teucro Telamonio, príncipe de hombres! Sigue
tirando flechas, por si acaso llegas á ser la aurora de salvación de los
dánaos y honras á tu padre Telamón, que te crió cuando eras niño y
te educó en su casa, á pesar de tu condición de bastardo; ya que
está lejos de aquí, cúbrele de gloria. Lo que voy á decir, se cumplirá:
Si Júpiter, que lleva la égida, y Minerva me permiten destruir la bien
edificada ciudad de Ilión, te pondré en la mano, como premio de
honor únicamente inferior al mío, ó un trípode, ó dos corceles con su
correspondiente carro, ó una mujer que comparta contigo el lecho.»
292 Respondióle el eximio Teucro: «¡Gloriosísimo Atrida! ¿Por
qué me instigas cuando ya, solícito, hago lo que puedo? Desde que
los rechazamos hacia Ilión mato hombres, valiéndome del arco.
Ocho flechas de larga punta tiré, y todas se clavaron en el cuerpo de
jóvenes llenos de marcial furor; pero no consigo herir á ese perro
rabioso.»
300 Dijo; y apercibiendo el arco, envió otra flecha á Héctor con
intención de herirle. Tampoco acertó; pero la saeta clavóse en el
pecho del eximio Gorgitión, valeroso hijo de Príamo y de la bella
Castianira, oriunda de Esima, cuyo cuerpo al de una diosa semejaba.
Como en un jardín inclina la amapola su tallo, combándose al peso
del fruto ó de los aguaceros primaverales; de semejante modo
inclinó el guerrero la cabeza que el casco hacía ponderosa.
309 Teucro armó nuevamente el arco, envió otra saeta á Héctor,
con ánimo de herirle, y también erró el tiro, por haberlo desviado
Apolo; pero hirió en el pecho cerca de la tetilla á Arqueptólemo,
osado auriga de Héctor, cuando se lanzaba á la pelea. Arqueptólemo
cayó del carro, cejaron los corceles de pies ligeros, y allí terminaron
la vida y el valor del guerrero. Hondo pesar sintió el espíritu de
Héctor por tal muerte; pero, aunque condolido del compañero,
dejóle y mandó á su propio hermano Cebrión, que se hallaba cerca,
que tomara las riendas de los caballos. Oyóle Cebrión y no
desobedeció. Héctor saltó del refulgente carro al suelo, y vociferando
de un modo espantoso, cogió una piedra y encaminóse hacia Teucro
con el propósito de herirle. Teucro, á su vez, sacó del carcaj una
acerba flecha, y ya estiraba la cuerda del arco, cuando Héctor, de
tremolante casco, acertó á darle con la áspera piedra cerca del
hombro, donde la clavícula separa el cuello del pecho y las heridas
son mortales, y le rompió el nervio: entorpecióse el brazo, Teucro
cayó de hinojos y el arco se le fué de las manos. Ayax no abandonó
al hermano caído en el suelo, sino que corriendo á defenderle, le
resguardó con el escudo. Acudieron dos compañeros, Mecisteo, hijo
de Equio, y el divino Alástor; y cogiendo á Teucro, que daba grandes
suspiros, lo llevaron á las cóncavas naves.
335 El Olímpico volvió á excitar el valor de los teucros, los cuales
hicieron arredrar á los aqueos en derechura al profundo foso. Héctor
iba con los delanteros, haciendo gala de su fuerza. Como el perro
que acosa con ágiles pies á un jabalí ó á un león, le muerde, ya los
muslos, ya las nalgas, y observa si vuelve la cara; de igual modo
perseguía Héctor á los aqueos de larga cabellera, matando al que se
rezagaba, y ellos huían espantados. Cuando atravesaron la
empalizada y el foso, muchos sucumbieron á manos de los teucros;
los demás no pararon hasta las naves, y allí se animaban los unos á
los otros, y con los brazos levantados oraban á todas las deidades.
Héctor hacía girar por todas partes los corceles de hermosas crines;
y sus ojos parecían los de la Gorgona ó los de Marte, peste de los
hombres.
350 Juno, la diosa de los níveos brazos, al ver á los aqueos
compadeciólos, y dirigió á Minerva estas aladas palabras:
352 «¡Oh dioses! ¡Hija de Júpiter, que lleva la égida! ¿No nos
cuidaremos de socorrer, aunque tarde, á los dánaos moribundos?
Perecerán, cumpliéndose su aciago destino, por el arrojo de un solo
hombre, de Héctor Priámida, que se enfurece de intolerable modo y
ha causado ya gran estrago.»
357 Respondióle Minerva, la diosa de los brillantes ojos: «Tiempo
ha que ése hubiera perdido fuerza y vida, muerto en su misma
patria por los aqueos; pero mi padre revuelve en su mente funestos
propósitos, ¡cruel, siempre injusto, desbaratador de mis planes!, y
no recuerda cuántas veces salvé á su hijo abrumado por los trabajos
que Euristeo le impusiera. Hércules clamaba al cielo, llorando, y
Júpiter me enviaba á socorrerle. Si mi sabia mente hubiese
presentido lo de ahora, no hubiera escapado el hijo de Júpiter de las
hondas corrientes de la Estigia, cuando aquél le mandó que fuera al
Orco, de sólidas puertas, y sacara del Érebo el horrendo can de
Plutón. Al presente Jove me aborrece y cumple los deseos de Tetis,
que besó sus rodillas y le tocó la barba, suplicándole que honrase á
Aquiles, asolador de ciudades. Día vendrá en que me llame
nuevamente su amada hija, la de los brillantes ojos. Pero unce los
solípedos corceles, mientras yo, entrando en el palacio de Júpiter,
me armo para la guerra; quiero ver si el hijo de Príamo, Héctor, de
tremolante casco, se alegrará cuando aparezcamos en el campo de
la batalla. Alguno de los teucros, cayendo junto á las naves aqueas,
saciará con su grasa y con su carne á los perros y á las aves.»
381 Dijo; y Juno, la diosa de los níveos brazos, no fué
desobediente. La venerable diosa Juno, hija del gran Saturno,
aprestó solícita los caballos de áureos jaeces. Y Minerva, hija de
Júpiter, que lleva la égida, dejó caer al suelo el hermoso peplo
bordado que ella misma tejiera y labrara con sus manos; vistió la
loriga de Jove, que amontona las nubes, y se armó para la luctuosa
guerra. Y subiendo al flamante carro, asió la lanza ponderosa, larga,
fornida, con que la hija del prepotente padre destruye filas enteras
de héroes cuando contra ellos monta en cólera. Juno picó con el
látigo á los bridones, y abriéronse de propio impulso, rechinando, las
puertas del cielo de que cuidan las Horas—á ellas está confiado el
espacioso cielo y el Olimpo—para remover ó colocar delante la densa
nube. Por allí, á través de las puertas, dirigieron aquellas deidades
los corceles, dóciles al látigo.
397 El padre Júpiter, apenas las vió desde el Ida, se encendió en
cólera; y al punto llamó á Iris, la de doradas alas, para que le
sirviese de mensajera:
399 «¡Anda, ve, rápida Iris! Haz que se vuelvan y no les dejes
llegar á mi presencia, porque ningún beneficio les reportará luchar
conmigo. Lo que voy á decir, se cumplirá: Encojaréles los briosos
corceles; las derribaré del carro, que romperé luego, y ni en diez
años cumplidos sanarán de las heridas que les produzca el rayo,
para que conozca la de los brillantes ojos que es con su padre contra
quien combate. Con Juno no me irrito ni me encolerizo tanto, porque
siempre ha solido oponerse á mis proyectos.»
409 De tal modo habló. Iris, la de los pies rápidos como el
huracán, se levantó para llevar el mensaje; descendió de los montes
ideos; y alcanzando á las diosas en la entrada del Olimpo, en valles
abundoso, hizo que se detuviesen, y les transmitió la orden de
Júpiter:
413 «¿Adónde corréis? ¿Por qué en vuestro pecho el corazón se
enfurece? No consiente el Saturnio que se socorra á los argivos. Ved
aquí lo que hará el hijo de Saturno, si cumple su amenaza: Os
encojará los briosos caballos, os derribará del carro, que romperá
luego, y ni en diez años cumplidos sanaréis de las heridas que os
produzca el rayo; para que conozcas tú, la de los brillantes ojos, que
es con tu padre contra quien combates. Con Juno no se irrita ni se
encoleriza tanto, porque siempre ha solido oponerse á sus
proyectos. Pero tú, temeraria, perra desvergonzada, si realmente te
atrevieras á levantar contra Júpiter la formidable lanza...»
425 Cuando esto hubo dicho, fuése Iris, la de los pies ligeros; y
Juno dirigió á Minerva estas palabras:
427 «¡Oh dioses! ¡Hija de Júpiter, que lleva la égida! Ya no
permito que por los mortales peleemos con Jove. Mueran unos y
vivan otros, cualesquiera que fueren; y aquél sea juez, como le
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

More Related Content

Similar to Testing Java Microservices Using Arquillian Hoverfly Assertj Junit Selenium And Mockito First Edition Alex Soto Bueno (20)

DOCX
Testing and Automation
Gulshan kumar Singh
 
PDF
Introducing Maven 1st Edition Balaji Varanasi Sudha Belida Auth
sblpeuj3241
 
PDF
Continuous Delivery For Kubernetes Chapters 1 2 Mauricio Salatino
dufloprial9b
 
PDF
When Developers Operate and Operators Develop
Adrian Cockcroft
 
PDF
Software Development 2020 - Swimming upstream in the container revolution
Bert Jan Schrijver
 
PDF
Swimming upstream in the container revolution
nextbuild
 
PDF
NextBuild 2015 - Swimming upstream in the container revolution
Bert Jan Schrijver
 
PDF
Cypress Testing Demystified: A Practical Guide
Testgrid.io
 
PDF
Adapting-Automation-to-the-available-workforce
Colm Harrington
 
PDF
MeetingPoint 2015 - Swimming upstream in the container revolution
Bert Jan Schrijver
 
PDF
From Monolith to Microservices - What Could Go Wrong?
Phuong Mai Nguyen
 
PDF
Patterns And Practices For Infrastructure As Code With Examples In Python And...
gbartrilar
 
PDF
The Future of Cloud Innovation, featuring Adrian Cockcroft
Dun & Bradstreet Cloud Innovation Center
 
PDF
Difference Between Agile And Scrum
Michelle Madero
 
PDF
AWS Community Day: From Monolith to Microservices - What Could Go Wrong?
Phuong Mai Nguyen
 
PDF
Containing your microservice sprawl
LibbySchulze
 
PDF
Testing primer
Chaitanya Kn
 
PDF
Software testing primer nick jenkins
Sachin MK
 
PDF
Testing primer
Cristiano Caetano
 
PDF
Selenium - The Way Of Success
Zbyszek Mockun
 
Testing and Automation
Gulshan kumar Singh
 
Introducing Maven 1st Edition Balaji Varanasi Sudha Belida Auth
sblpeuj3241
 
Continuous Delivery For Kubernetes Chapters 1 2 Mauricio Salatino
dufloprial9b
 
When Developers Operate and Operators Develop
Adrian Cockcroft
 
Software Development 2020 - Swimming upstream in the container revolution
Bert Jan Schrijver
 
Swimming upstream in the container revolution
nextbuild
 
NextBuild 2015 - Swimming upstream in the container revolution
Bert Jan Schrijver
 
Cypress Testing Demystified: A Practical Guide
Testgrid.io
 
Adapting-Automation-to-the-available-workforce
Colm Harrington
 
MeetingPoint 2015 - Swimming upstream in the container revolution
Bert Jan Schrijver
 
From Monolith to Microservices - What Could Go Wrong?
Phuong Mai Nguyen
 
Patterns And Practices For Infrastructure As Code With Examples In Python And...
gbartrilar
 
The Future of Cloud Innovation, featuring Adrian Cockcroft
Dun & Bradstreet Cloud Innovation Center
 
Difference Between Agile And Scrum
Michelle Madero
 
AWS Community Day: From Monolith to Microservices - What Could Go Wrong?
Phuong Mai Nguyen
 
Containing your microservice sprawl
LibbySchulze
 
Testing primer
Chaitanya Kn
 
Software testing primer nick jenkins
Sachin MK
 
Testing primer
Cristiano Caetano
 
Selenium - The Way Of Success
Zbyszek Mockun
 

Recently uploaded (20)

PPTX
Presentation: Climate Citizenship Digital Education
Karl Donert
 
PPTX
HEAD INJURY IN CHILDREN: NURSING MANAGEMENGT.pptx
PRADEEP ABOTHU
 
PDF
ARAL-Orientation_Morning-Session_Day-11.pdf
JoelVilloso1
 
PPSX
HEALTH ASSESSMENT (Community Health Nursing) - GNM 1st Year
Priyanshu Anand
 
PPTX
HYDROCEPHALUS: NURSING MANAGEMENT .pptx
PRADEEP ABOTHU
 
PPTX
Latest Features in Odoo 18 - Odoo slides
Celine George
 
PPTX
Optimizing Cancer Screening With MCED Technologies: From Science to Practical...
i3 Health
 
PPTX
Views on Education of Indian Thinkers J.Krishnamurthy..pptx
ShrutiMahanta1
 
PDF
The-Beginnings-of-Indian-Civilisation.pdf/6th class new ncert social/by k san...
Sandeep Swamy
 
PPTX
A PPT on Alfred Lord Tennyson's Ulysses.
Beena E S
 
PPTX
Views on Education of Indian Thinkers Mahatma Gandhi.pptx
ShrutiMahanta1
 
PPTX
Pyhton with Mysql to perform CRUD operations.pptx
Ramakrishna Reddy Bijjam
 
PPTX
How to Configure Lost Reasons in Odoo 18 CRM
Celine George
 
PDF
DIGESTION OF CARBOHYDRATES,PROTEINS,LIPIDS
raviralanaresh2
 
PPTX
Optimizing Cancer Screening With MCED Technologies: From Science to Practical...
i3 Health
 
PDF
IMP NAAC REFORMS 2024 - 10 Attributes.pdf
BHARTIWADEKAR
 
PPTX
Growth and development and milestones, factors
BHUVANESHWARI BADIGER
 
PDF
BÀI TẬP BỔ TRỢ THEO LESSON TIẾNG ANH - I-LEARN SMART WORLD 7 - CẢ NĂM - CÓ ĐÁ...
Nguyen Thanh Tu Collection
 
PPTX
ROLE OF ANTIOXIDANT IN EYE HEALTH MANAGEMENT.pptx
Subham Panja
 
PPTX
How to Configure Access Rights of Manufacturing Orders in Odoo 18 Manufacturing
Celine George
 
Presentation: Climate Citizenship Digital Education
Karl Donert
 
HEAD INJURY IN CHILDREN: NURSING MANAGEMENGT.pptx
PRADEEP ABOTHU
 
ARAL-Orientation_Morning-Session_Day-11.pdf
JoelVilloso1
 
HEALTH ASSESSMENT (Community Health Nursing) - GNM 1st Year
Priyanshu Anand
 
HYDROCEPHALUS: NURSING MANAGEMENT .pptx
PRADEEP ABOTHU
 
Latest Features in Odoo 18 - Odoo slides
Celine George
 
Optimizing Cancer Screening With MCED Technologies: From Science to Practical...
i3 Health
 
Views on Education of Indian Thinkers J.Krishnamurthy..pptx
ShrutiMahanta1
 
The-Beginnings-of-Indian-Civilisation.pdf/6th class new ncert social/by k san...
Sandeep Swamy
 
A PPT on Alfred Lord Tennyson's Ulysses.
Beena E S
 
Views on Education of Indian Thinkers Mahatma Gandhi.pptx
ShrutiMahanta1
 
Pyhton with Mysql to perform CRUD operations.pptx
Ramakrishna Reddy Bijjam
 
How to Configure Lost Reasons in Odoo 18 CRM
Celine George
 
DIGESTION OF CARBOHYDRATES,PROTEINS,LIPIDS
raviralanaresh2
 
Optimizing Cancer Screening With MCED Technologies: From Science to Practical...
i3 Health
 
IMP NAAC REFORMS 2024 - 10 Attributes.pdf
BHARTIWADEKAR
 
Growth and development and milestones, factors
BHUVANESHWARI BADIGER
 
BÀI TẬP BỔ TRỢ THEO LESSON TIẾNG ANH - I-LEARN SMART WORLD 7 - CẢ NĂM - CÓ ĐÁ...
Nguyen Thanh Tu Collection
 
ROLE OF ANTIOXIDANT IN EYE HEALTH MANAGEMENT.pptx
Subham Panja
 
How to Configure Access Rights of Manufacturing Orders in Odoo 18 Manufacturing
Celine George
 
Ad

Testing Java Microservices Using Arquillian Hoverfly Assertj Junit Selenium And Mockito First Edition Alex Soto Bueno

  • 1. Testing Java Microservices Using Arquillian Hoverfly Assertj Junit Selenium And Mockito First Edition Alex Soto Bueno download https://ebookbell.com/product/testing-java-microservices-using- arquillian-hoverfly-assertj-junit-selenium-and-mockito-first- edition-alex-soto-bueno-55587642 Explore and download more ebooks at ebookbell.com
  • 2. Here are some recommended products that we believe you will be interested in. You can click the link to download. Testing Java Microservices Using Arquillian Hoverfly Assertj Junit Selenium And Mockito 1st Edition Andy Gumbrecht https://ebookbell.com/product/testing-java-microservices-using- arquillian-hoverfly-assertj-junit-selenium-and-mockito-1st-edition- andy-gumbrecht-7261950 Java Testing With Spock Konstantinos Kapelonis Luke Daley https://ebookbell.com/product/java-testing-with-spock-konstantinos- kapelonis-luke-daley-5470386 Java Testing Design And Automation Illustrated Edition Frank Cohen https://ebookbell.com/product/java-testing-design-and-automation- illustrated-edition-frank-cohen-974486 Java Testing With Selenium A Comprehensive Syntax Guide For Automation https://ebookbell.com/product/java-testing-with-selenium-a- comprehensive-syntax-guide-for-automation-57865422
  • 3. Testng Java Testing Framework Tutorials Point https://ebookbell.com/product/testng-java-testing-framework-tutorials- point-12142790 Next Generation Java Testing Testng And Advanced Concepts Beust https://ebookbell.com/product/next-generation-java-testing-testng-and- advanced-concepts-beust-22041386 Penetration Testing With Java A Stepbystep Pen Testing Handbook For Java Applications Nancy Snoke https://ebookbell.com/product/penetration-testing-with-java-a- stepbystep-pen-testing-handbook-for-java-applications-nancy- snoke-232021524 Unit Testing In Java How Tests Drive The Code 1st Edition Johannes Link https://ebookbell.com/product/unit-testing-in-java-how-tests-drive- the-code-1st-edition-johannes-link-979056 Pragmatic Unit Testing In Java 8 With Junit Jeff Langr Andy Hunt https://ebookbell.com/product/pragmatic-unit-testing-in-java-8-with- junit-jeff-langr-andy-hunt-38623494
  • 6. Copyright For online information and ordering of this and other Manning books, please visit www.manning.com. The publisher offers discounts on this book when ordered in quantity. For more information, please contact Special Sales Department Manning Publications Co. 20 Baldwin Road PO Box 761 Shelter Island, NY 11964 Email: [email protected] ©2018 by Manning Publications Co. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by means electronic, mechanical, photocopying, or otherwise, without prior written permission of the publisher. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in the book, and Manning Publications was aware of a trademark claim, the designations have been printed in initial caps or all caps. Recognizing the importance of preserving what has been written, it is Manning’s policy to have the books we publish printed on acid­free paper, and we exert our best efforts to that end. Recognizing also our responsibility to conserve the resources of our planet, Manning books are printed on paper that is at least 15 percent recycled and processed without the use of elemental chlorine. ayl sts story opics torials fers & Deals ghlights ttings Support Sign Out Manning Publications Co. 20 Baldwin Road PO Box 761 Shelter Island NY 11964 ,
  • 7. Development editor: Cynthia Kane Technical development editor: Adam Scheller Project editor: Tiffany Taylor Copyeditor: Tiffany Taylor Proofreader: Katie Tennant Technical proofreader: Joshua White Typesetter: Gordan Salinovic Cover designer: Marija Tudor ISBN 9781617292897 Printed in the United States of America 1 2 3 4 5 6 7 8 9 10 – DP – 23 22 21 20 19 18
  • 8. Brief Table of Contents Copyright Brief Table of Contents Chapter 1. An introduction to microservices Chapter 2. Application under test Chapter 3. Unit­testing microservices Chapter 4. Component­testing microservices Chapter 5. Integration­testing microservices Chapter 6. Contract tests Chapter 7. End­to­end testing Chapter 8. Docker and testing Chapter 9. Service virtualization Chapter 10. Continuous delivery in microservices Playlists History Topics Tutorials Appendix. Masking multiple containers with Arquillian Chameleon
  • 9. Chapter 1. An introduction to microservices This chapter covers Why move toward a new microservice architecture? What microservices are today, and where the future may lead The basic component makeup of a microservice Testing strategies Traditional monolithic applications are deployed as a single package, usually as a web or enterprise­archive file (WAR or EAR). They contain all the business logic required to complete multiple tasks, often alongside the components required to render the user interface (UI, or GUI for graphical user interface). When scaling, this usually means taking a complete copy of that entire application archive onto a new server node (basically, deploying it to another server node in a cluster). It doesn’t matter where the load or bottleneck is occurring; even if it’s only in a small cross section of the application, scaling this way is an all­or­nothing approach. Microservices are specifically designed to target and change this all­or­nothing aspect by allowing you to break your business logic into smaller, more manageable elements that can be employed in multiple ways. This book isn’t intended to be a tutorial on the varied microservice architectures that are available today; we’ll assume you have some understanding of the subject. Rather, we’re going to help you overcome the challenges involved in testing the common features that all microservice applications share. In order to do that, in this chapter we’ll establish some common ground about what a microservice is, so that you can relate to where we’re coming from when we discuss these topics in later chapters. Shifting toward the ever­more­popular microservice architecture means you need to adopt new strategies in development, testing, and restructuring/refactoring and move away from some of the purely monolithic­application practices. Microservices offer you the advantage of being able to scale individual services, and the Playlists History Topics Tutorials Offers & Deals Highlights Settings Support Sign Out
  • 10. ability to develop and maintain multiple services in parallel using several teams, but they still require a robust approach when it comes to testing. In this book, we’ll discuss various approaches for using this new, more focused way of delivering tightly packaged “micro” services and how to resolve the complex testing scenarios that are required to maintain stability across multiple teams. Later chapters will introduce an example application and how to develop testing strategies for it; this will help you better understand how to create your own test environments. You’ll see and use many features of the Arquillian test framework, which was specifically designed to tackle many of the common testing challenges you’ll face. An array of mature extensions have been developed over the years, and although other tools are available, Arquillian is our tool of choice—so expect some bias. That said, Arquillian also provides close integration with many testing tools you may already be familiar with. A note about software versions This book uses many different software packages and tools, all of which change periodically. We tried throughout the book to present examples and techniques that wouldn’t be greatly affected by these changes. All examples require Java 8, although when we finished the book, Java 10 had been released. We haven’t updated the examples because in terms of testing microservices, the release doesn’t add anything new. Something similar is true for JUnit 5. All of the examples are written using JUnit 4.12, because when we started writing the book, JUnit 5 wasn’t yet in development. At the time we finished the book, not all of the frameworks explained here have official support for JUnit 5, so we decided to skip updating the JUnit version. Other libraries, such as Spring Boot and Docker (Compose), have evolved as well during the development of the book, but none of these changes have a significant impact on how to write tests. 1.1. WHAT ARE MICROSERVICES, AND WHY USE THEM? In this section, we present what we believe is a reasonably good interpretation of the currently available answers to these questions. What you learn will provide a solid basis for understanding the microservice architecture, but expect innovation over time. We won’t make any predictions: as stated, our principle focus for the book is testing microservices, which is unlikely to change in any significant way.
  • 11. It isn’t important that you fully understand the microservice architecture at this point. But if, after reading this chapter, the term microservice is still a dark void for you, we encourage you to gather more information from your own sources. Tip You may find it useful to join the open discussions at MicroProfile (http://microprofile.io). This is an initiative by the likes of IBM, London Java Community (LJC), RedHat, Tomitribe, Payara, and Hazelcast to develop a shared definition of Enterprise Java for microservices, with the goal of standardization. 1.1.1. Why use microservices? Before we delve into the nature of microservices, let’s answer the “why” question. Until recently, it’s been commonplace to develop monolithic applications, and that’s still perfectly acceptable for any application that doesn’t require scaling. The problem with scaling any kind of monolithic application is straightforward, as shown in figure 1.1. Microservices aren’t here to tell you that everything else is bad; rather, they offer an architecture that is far more resilient than a monolith to changes in the future. Figure 1.1. Scaling a monolithic application
  • 12. Microservices enable you to isolate and scale smaller pieces of your application, rather than the entire application. Imagine that you’ve extracted some core business logic in your application to services A and B. Let’s say service A provides access to an inventory of items, and B provides simple statistics. You notice that on average, service A is called one million times per hour and service B is called only once per day. Scaling a monolithic application would mean adding a new node with the application that includes both services A and B. Wouldn’t it be better if you only needed to scale service A? This is where the potential of microservices becomes apparent: in the new architecture, shown in figure 1.2, services A and B become microservices A and B. You can still scale the application, but this additional flexibility is the point: you can now choose to scale where the load is greatest. Even better, you can dedicate one team of developers to maintaining microservice A and another to microservice B. You don’t need to touch the application to add features or fix bugs in either A or B, and they can also be rolled out completely independently of each other. Figure 1.2. Scaling a microservice independently of the main application
  • 13. Companies like Netflix, Google, Amazon, and eBay have based much of their platforms on a microservice architecture, and they’ve all been kind enough to share much of this information freely. But although considerable focus is placed on web applications, you can apply a microservice architecture to any application. We hope this whets your appetite! 1.1.2. What are microservices? At first glance, the term micro may conjure up images of a tiny application with a small footprint. But regarding application size, there are no rules, other than a rule of thumb. A microservice may consist of several, several hundred, or even several thousand lines of code, depending on your specific business requirements; the rule of thumb is to keep the logic small enough for a single team to manage. Ideally, you should focus on a single endpoint (which may in turn provide multiple resources); but again, there’s no hard­ and­fast rule. It’s your party. The most common concept is that a single application should be the uppermost limit of a microservice. In the context of a typical application server running multiple applications, this means splitting applications so they’re running on a single application server. In theory, think of your first microservice as a single piece of a jigsaw puzzle, and try to imagine how it will fit together with the next piece. You can break a monolithic application into its logical pieces, as shown in figure 1.3. There should be just enough information within each piece of the puzzle to enable you to build the greater picture. In a microservice architecture, these pieces are much more loosely coupled; see figure 1.4. Figure 1.3. Each service is part of the big picture.
  • 14. Figure 1.4. Each microservice is still part of the picture but is isolated within a separate environment. 1.1.3. Continuous integration, deployment, and Docker The decoupling of application elements into scalable microservices means you’ll have to start thinking about the continuous integration (CI) and continuous delivery (CD) pipelines from an early stage. Instead of one build script and one deployment, you’ll need multiple independent builds that must be sewn together for integration testing and deployment to different hosts.
  • 15. You’ll find that far less work is involved than you may think. This is largely due to the fact that a microservice is, for all intents and purposes, an application like any other. The only difference is that a microservice packages the application together with its runtime environment. The easiest and most recognized way to do this today is to create and deploy a microservice as a Docker image (www.docker.com). Note Docker is the world’s leading software­containerization platform. If you’re not sure what Docker is, then at some point please visit www.docker.com and follow the “What is Docker?” tutorial. Don’t worry, though—we’ll guide you through this pipeline when we put all the microservice elements together toward the end of the book. The heavyweight CI/CD contenders are Travis (https://travis­ci.org), Bamboo (https://de.atlassian.com/software/bamboo), and Jenkins (https://jenkins.io). They all provide great support for microservices and deployment pipelines for Docker images; but in this book, we’ll use Jenkins, because it’s open source and has a huge community. It’s not necessarily the easiest to use, but it offers by far the most features via plugins. In chapter 8, we’ll highlight all the involved technologies in detail and guide you through the development of a viable CI/CD pipeline. 1.2. MICROSERVICE NETWORKS AND FEATURES Microservices are loosely coupled, which leads to new questions. How are microservices coupled, and what features does this architecture offer? In the following sections, we’ll look at some answers. But for all intents and purposes, each microservice is isolated by a network boundary. 1.2.1. Microservice networks Microservices are most commonly integrated over a RESTful (Representational State Transfer) API using HTTP or HTTPS, but they can be connected by anything that’s considered a protocol to access an endpoint to a resource or function. This is a broad topic, so we’re only going to discuss and demonstrate Java REST using JAX­RS. Tip If you’re unfamiliar with RESTful web services using JAX­RS (https://jax­rs­
  • 16. spec.java.net), now would be a good time to read up on these topics. With this information, your initial ideas for microservices should be starting to take form. Let’s continue with our earlier example. Microservice A, the inventory service, is isolated by a network layer from the UI and from microservice B, the statistics service. B communicates with A to collect statistics using the defined request­and­response protocols. They each have their own domain and external resources and are otherwise completely separate from each other. The UI service is able to call both A and B to present information in a human­readable form, a website, or a heavy client, as shown in figure 1.5. Figure 1.5. Each service communicates by defined protocols. Hypermedia Services should be developed with hypermedia in mind. This is the latest buzzword; it implies that services should be self­documenting in their architecture, by providing links to related resources in any response. Currently there’s no winner in this category, and it would be unfair to start placing bets now, but you can take a look at the front runners and make an educated guess: JSON­LD (http://json­ld.org), JSON Hypertext Application Language (HAL, https://tools.ietf.org/html/draft­kelly­json­hal­08), Collection+JSON (https://github.com/collection­json/spec), and Siren
  • 17. (https://github.com/kevinswiber/siren). Tests must be designed to cover comprehensively any and all interaction with external services. It’s important to get this right, because network interaction will always present its own set of challenges. We’ll cover this extensively in chapter 5. By now it should be clear that a microservice can be large in terms of application size, and that “micro” refers to the public­facing surface area of the application. Cloud space is cheap today, so the physical size of a microservice is less relevant than in the past. Another concern that we often hear mentioned is, “What about network speed?” Microservices are generally hosted in the same local network, which is typically Gigabit Ethernet or better. So, from a client perspective, and given the ease of scaling microservices, response times are likely to be much better than expected. Again, don’t take our word for it; think of Netflix, Google, Amazon/AWS, and eBay. 1.2.2. Microservice features In our example, both microservices A and B can be developed independently and deployed by two entirely different teams. Each team only needs to understand the resource­component layer of the microservice on which they’re working, rather than the entire business­domain component. This is the first big win: development can be much faster and easier to understand in the given context. JavaScript Object Notation (JSON, www.json.org) and Extensible Markup Language (XML, www.w3.org/XML) are the common resource languages, so it’s easy to write clients for such services. Some cases may dictate a different approach, but the basic scenarios remain essentially the same: the endpoints are accessible from a multitude of devices and clients using defined protocols. Multiple microservices form a network of connected applications, where each individual microservice can be scaled independently. Elastic deployment on the cloud is now commonplace, and this enables an individual service to scale automatically up or down—for example, based on load. Some other interesting benefits of microservices are improved fault isolation and memory management. In a monolithic application, a fault in a single component can bring down an entire server. With resilient microservices, the larger part of the picture will continue to function until the misbehaving service issue is resolved. In figure 1.6, is the statistics service really necessary for the application to function as a whole, or can
  • 18. you live without it for a while? Figure 1.6. Resilient design using circuit breakers Of course, as is the nature of all good things, microservices have drawbacks. Developers need to learn and understand the complexities of developing a distributed application, including how best to use IDEs, which are often orientated toward monolithic development. Developing use cases spanning multiple services that aren’t included in distributed transactions requires more thought and planning than for a monolith. And testing is generally more difficult, at least for the connected elements, which is why we wrote this book. 1.3. MICROSERVICE ARCHITECTURE The anatomy of a microservice can be varied, as shown in figure 1.7, but design similarities are bound to occur. These elements can be grouped together to form the application­component layers. It’s important to provide test coverage at each layer, and you’ll likely be presented with new challenges along the way; we’ll address these challenges and offer solutions throughout the book. Figure 1.7. The basic microservice components
  • 19. Let’s look at these microservice component layers from the top down. Note A microservice should encapsulate and expose a well­defined area of logic as a service. That doesn’t mean that you can’t allow interaction from other systems by other means. For example, your service may expose specific documents that are stored in Elasticsearch (ES). In such a case, it’s perfectly legitimate for other applications to talk natively to ES in order to seed the documents. 1.3.1. Resource component Resources are responsible for exposing the service interaction via a chosen protocol. This interaction occurs using mapped objects, usually serialized using JSON or XML. These mapped objects represent the input and/or output of the business domain. Sanitization of the incoming objects and construction of the protocol­specific response usually occur at this layer; see figure 1.8. Figure 1.8. The resource component publicly exposes the service.
  • 20. Note Now that we’re here, it’s worth mentioning that the resource­component layer is the layer that puts the micro in microservice. For the rest of this book, and for the sake of simplicity, we’ll focus on the most common form of resource providers today: RESTful endpoints. If you aren’t familiar with RESTful web services, please take the time to research and understand this important topic. See “What Are RESTful Web Services?” in the Java EE 6 tutorial, http://mng.bz/fIa2. 1.3.2. Business-domain component The business­domain component is the core focus of your service application and is highly specific to the logical task for which the service is being developed. The domain may have to communicate with various other services (including other microservices) in order to calculate a response or process requests to and from the resource component; see figure 1.9. Figure 1.9. The business-domain component is your service’s business logic. A bridge is likely to be required between the domain component and the resource component, and possibly the remote component. Most microservices need to communicate with other microservices at some point. 1.3.3. Remote resources component This component layer is where your piece of the jigsaw puzzle may need to connect to the next piece, or pieces, of the picture. It consists of a client that understands how to send and receive resource objects to and from other microservice endpoints, which it then translates for use in the business component layer; see figure 1.10. Figure 1.10. The remote resources component is the gateway to other services. [ 1 ] 1
  • 21. Due to the nature of remote resources, you must pay special attention to creating a resilient design. A resilient framework is designed to provide features such as circuit breakers and timeout fallbacks in the event of a failure. Don’t try to reinvent the wheel: several resilient frameworks are available to choose from, including our top pick, Hystrix (https://github.com/Netflix/Hystrix/wiki), which is open source and contributed by Netflix. A gateway service should act as a bridge between the domain component and the client component. It’s responsible for translating request­and­response calls to and from any remote resource via the client. This is the best place to provide a graceful failure if the resource can’t be reached. The client is responsible for speaking the language of your chosen protocol. Nine times out of ten, this will be JAX­RS (https://jax­rs­spec.java.net) over HTTP/S for RESTful web services. We highly recommend the open source services framework Apache CXF (http://cxf.apache.org) for this layer, because it’s fully compliant with JAX­WS, JAX­RS, and others, and it won’t tie you down to a specific platform. 1.3.4. Persistence component More often than not, an application requires some type of persistence or data retrieval (see figure 1.11). This usually comes in the form of an object­relational mapping (ORM) mechanism, such as the Java Persistence API (JPA), but could be something as simple as an embedded database or properties file. See “Hibernate ORM: What Is Object/Relational Mapping?” http://hibernate.org/orm/what­is­an­orm. See “Introduction to the Java Persistence API” in the Java EE 6 tutorial, http://mng.bz/Cy69. Figure 1.11. The persistence component is for data storage. [ 2 ] [ 3 ] 2 3
  • 22. 1.4. MICROSERVICE UNIT TESTING Chapter 3 will take a deep dive into real unit­testing scenarios. The next few paragraphs are an introduction to the terminology we’ll use and what to expect as you develop your testing strategies. A typical unit test is designed to be as small as possible and to test a trivial item: a unit of work. In the microservice context, this unit of work may be more difficult to represent, due to the fact that there’s often much more underlying complexity to the service than is apparent at first glance. Unit testing can often lead to the conclusion that you need to refactor your code in order to reduce the complexity of the component under test. This also makes testing useful as a design tool, especially when you’re using test­driven development (TDD). A beneficial side effect of unit testing is that it lets you continue developing an application while detecting regressions at the same time. Although you’re likely to encounter more­detailed scenarios along the way, there are basically two styles of unit testing: sociable and solitary. These styles are loosely based on whether the unit test is isolated from its underlying collaborators. Both styles are nonexclusive, and they complement each other nicely. You should count on using both, depending on the nature of the testing challenge. We’ll expand on these concepts throughout the book. 1.4.1. Solitary unit tests Solitary unit testing should focus on the interaction around a single object class. The test should encompass only the class’s own dependents or dependencies on the class. You’ll usually test resource, persistence, and remote components using solitary tests, because those components rarely need to collaborate with each other; see figure 1.12. Figure 1.12. Predominantly solitary unit-test components
  • 23. You need to isolate individual classes for testing by stubbing or mocking all collaborators within that class. You should test all the methods of the class, but not cross any boundaries to other concrete classes. Basically, this means all injected fields should receive either a mock or stubbed implementation that only returns canned responses. The primary aim is for the code coverage of the class under test to be as high as possible. 1.4.2. Sociable unit tests Sociable unit testing focuses on testing the behavior of modules by observing changes in their state. This approach treats the unit under test as a black box tested entirely through its interface. The domain component is nearly always a candidate for sociable testing, because it needs to collaborate in order to process a request and return a response; see figure 1.13. Figure 1.13. Predominantly sociable unit-test component You may still need to stub or mock some complex collaborators of the class under test, but this should be as far along as possible within the hierarchy of collaborating objects. You shouldn’t only be testing that a specific class sends and receives correct payloads, but also that the class collaborators are operating as expected within the class. The test coverage should ideally include all models, variables and fields as well as the class collaborators. It’s also important to test that the class can correctly handle any
  • 24. response, including invalid responses (negative testing). SUMMARY A microservice is a part of a monolithic application that has been dissected into a smaller logical element. Microservices benefit your application by allowing targeted scaling and focused development. Microservices offer a logical way to meet scalability requirements by providing the ability to scale not only where performance is required, but also when. You can break monolithic applications into smaller elements that can be used as microservices. Microservices allow several teams to focus on individual, nonconflicting tasks that make up the bigger picture. Solitary unit tests are used for components that don’t store state or don’t need to collaborate in order to be tested. Sociable unit tests are used for components that must collaborate or store state in order to be tested.
  • 25. Chapter 2. Application under test This chapter covers Exploring a sample application Understanding critical parts of the code Developing microservices with Java EE and Spring Boot The previous chapter introduced you to microservices, including their basic anatomy and architecture. This introduction was intended to give you insight into the kinds of tests you might need to write for a microservice­based architecture. This chapter introduces the application that will be used throughout the book to demonstrate the development and testing of a microservices architecture. Our goal is to provide an easy­to­follow example that will help you understand the relevance of each kind of test that will be applied. We try to follow best practices for a microservices architecture, but we make some design choices for the sake of simplicity and also purely for educational purposes. For instance, we may use more technologies than necessary, or simplify the number of layers used in a microservice because they don’t add value from a testing point of view. In such cases, we point out the reason for a particular approach and discuss how to perform these tasks in real­world programming. It’s ultimately your responsibility as a developer to choose the appropriate tools to use, but we always offer a recommended approach. 2.1. GETTING STARTED The example application, Gamer, is a simple software portal for gamers. Its purpose is to expose information about software games and to let gamers not only read important facts about games and watch videos of games being played, but also comment on and leave a star rating for played games. Although this application is intentionally simple, it covers all the main topics needed to showcase the microservices architecture. Throughout the book, we’ll guide you through the various kinds of tests to be written for a microservices­based application. Playlists History Topics Tutorials Offers & Deals Highlights Settings Support Sign Out
  • 26. We’ll start by providing some use cases for the Gamer app, to get a high­level view of the actions a gamer can take. Gamers want to be able to do these things: Search for games by name, so they can see a list of games that match their interests Read about important aspects of a game, such as its publication date and which platforms are supported Read other gamers’ comments about a game, to help them decide whether they’ll enjoy it and want to buy it Write comments about a game, so other gamers can benefit from their evaluation of it Assign a star rating to a game and quickly see the games with the highest ratings Watch game­related videos such as trailers, tutorials, and real in­game play Let’s begin by defining the data required for this application. We won’t focus on technical details just yet—this section only describes the conceptual data model. The main entity is a game. Table 2.1 shows the parts that make up a game. Table 2.1. The parts of a game Field Description title String representing the name of the game cover URL of an image of the game cover ReleaseDate The game’s release date Publisher The game’s publisher Developer The game’s developer Table 2.2 shows the parts that make up a release date. Table 2.2. Parts of a release date Field Description platform Platform name under which the game was released date Date (day, month, and year) when the game was released for a platform Table 2.3 shows the parts that make up a comment. Table 2.3. Parts of a comment
  • 27. Field Description comment String containing the comment message rate Star rating from 1 to 5, indicating the overall quality of the game Now that you understand the kinds of data the Gamer app will manage, we can go a little deeper and inspect the architecture of the application. 2.2. PREREQUISITES This book isn’t a Java tutorial. If you’re not already familiar with Java as a language, then you’re highly unlikely to have an enjoyable read. That said, we hope to present information that’s of use to readers with all levels of interest. The Java tutorials at https://docs.oracle.com/javase/tutorial are outstanding resources for any aspiring Java developer and a fantastic reference for everyone who uses Java. The book also isn’t an academic masterpiece. The authors are primarily developers, and English isn’t the first language for some of us. We like getting our hands dirty, and we hope you do too. We expect you to bring an open mind and understand that not everyone may share our opinions. There’s never one way that’s entirely right or entirely wrong, and our suggestions are presented as food for thought for your creative mind. Note Much of the source code is formatted based on the restrictions of presenting it on a printed page. This can lead to verbose layout. Feel free to adjust the code formatting to your own preferences. 2.2.1. Java Development Kit You’ll need at least version SE (Standard Edition) 8 of the Java Development Kit (JDK) to compile and run the code in this book. You can always find the latest Oracle JDK (recommended) at http://mng.bz/83Ct or the OpenJDK at http://openjdk.java.net. To test for Java, run the following command, which should display results similar to the following, depending on your installed version: $ java ­version
  • 28. java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121­b13) Java HotSpot(TM) 64­Bit Server VM (build 25.121­b13, mixed mode) 2.2.2. Build tools We’re using both Apache Maven (https://maven.apache.org) and Gradle (https://gradle.org) to build several of the project modules. Make sure you’ve installed both of these tools by following the instructions provided on the corresponding websites. To test for a correct Maven installation, run the following command: $ mvn ­version Apache Maven 3.3.9 ... For Gradle, run this command: $ gradle ­v ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ Gradle 3.2.1 ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ 2.2.3. Environment variables The full application requires two API keys in order to access some remote resources. The API keys are registered to individual user accounts, so we can’t provide shared keys here. It’s not necessary to obtain these keys in order to run most of the test examples provided in this book. But if you wish to experiment with the code, we suggest that you obtain the keys and create the corresponding environment variables. To obtain an API key for YouTube, visit https://developers.google.com/youtube/v3/getting­started and follow the instructions in the Before You Start section. To obtain an API key for the Internet Game Database (IGDB), visit https://igdb.github.io/api/about/welcome or go directly to https://api.igdb.com to register for access. Once you have your own API keys, add them to your environment variables. On Linux, add the following in /home/profile:
  • 29. ... export YOUTUBE_API_KEY="Your­Key" export IGDB_API_KEY="YourKey" Windows users may find the following link useful for configuring environment variables: http://mng.bz/1a2K. William R. Stanek, “Configuring System and User Environment Variables,” MSDN, from Microsoft Windows 2000 (Microsoft Press, 2002). 2.2.4. Integrated development environment (IDE) None of the application code requires you to use an IDE. Notepad will do. Of course, feel free to open the projects using your favorite IDE (that supports Maven­ and Gradle­based projects). If you want to add breakpoints in the code in order to follow the execution path (highly recommended), then we suggest using an IDE. We’ve tested the code in the following IDEs, in no particular order of preference: IntelliJ IDEA (www.jetbrains.com/idea) NetBeans (https://netbeans.org) Eclipse (www.eclipse.org/downloads) 2.3. ARCHITECTURE As mentioned at the beginning of the chapter, the Gamer app follows a microservices architecture. The first thing to do is identify which services make up the application. For this app, we concluded that splitting the domain into four distinct microservices was required: Game service—Provides all the information related to games. It includes queries for obtaining a game ID by a specific name, or returns information for a specific game ID. Comments service—Adds star ratings and comments for a specific game, as well as retrieves them. Video service—Returns the location of the three most prominent videos for a game. Aggregator service—Calls the aforementioned named services, and aggregates the data of each service into a single response. [ 1 ] 1
  • 30. The application schema is shown in figure 2.1. Figure 2.1. Gamer application schema As you can see, a frontend (typically a browser) consumes the information provided by the Gamer API. The point of entry is the aggregator service, which communicates with the game, video, and comments services to get or insert required data for games. The aggregator service compiles all the data into a single response and returns this to the frontend. You can now understand the application architecture and the technical reasons behind the decisions that were made for each service. Note At first, please skip the tests when you build the application from the command line or IDE. To demonstrate a point, and also to provide exercises, some of the tests won’t complete as provided. As your knowledge builds throughout the book, you’ll be in a better position to play with and expand the sample code. 2.3.1. The game service Install the game service using the following code: cd ./game mvn install ­DskipTests The game service is a Java EE 7 application running on WildFly Swarm that’s responsible for providing all the information related to games. It provides two operations to retrieve this information: Getting a list of games by title (multiple games can have the same title). The information provided for this endpoint must be minimal: for example, only the identifier and/or title of the game.
  • 31. Returning detailed information about a game by specifying a known game identifier. You might have noticed that there’s no operation for inserting games. This is because the game service acts as a proxy/cache to an external service API. An external service is a service that’s out of the current application scope, that’s developed and maintained by a third party, and to which you’re merely a subscriber. Typical examples of these services are search engines, weather forecasts, and geospatial calculations. This service example relies on the Internet Game Database website (www.igdb.com) to provide all of the required game data. The Internet Game Database API IGDB is a video game database, intended for use by both game consumers and video game professionals. In addition to serving as a portal for getting information about games, the site provides a public REST API (www.igdb.com/api) that lets you access data for games registered on the site. To authorize access to the REST API, you need to register on the site and request a new API key. This key must be passed in each call as an HTTP header. During the course of the book, we provide more information about the IGDB REST API, such as how to authenticate against IGDB, and the required format for resource endpoints. When you rely on external calls to third­party services, it’s always important (if possible) to cache as much data from the external service as you can. This is important for three reasons: You avoid round trips to external networks, which is typically a slow operation. If you have quota/metered access to the external API, you save on hits to the service. In the event the external service experiences an outage, your application can continue to work with cached data. Warning
  • 32. Generally, caching is used only in cases where the external data doesn’t change often or you can replicate all the data on your systems. To maintain coherence of the external data, you should apply a periodic refresh strategy to the cache so it doesn’t become outdated. For the sake of simplicity, no refresh strategy is implemented in the example app, but this is something to take into consideration in a real­world scenario. In this microservice, a cache­persistence­layer system is implemented using the light SQL database H2 (www.h2database.com/html/main.html). The entity­relationship (ER) model used in the game service is composed of four entities, described in tables 2.4–2.7. Figure 2.2 shows this in graphical terms. Table 2.4. Game table Field Data type Description id Long Game identifier. version Int Internal field for avoiding conflicts in optimistic locking. title String Name of the game. This value is unique. cover String URL of the cover of the game, or null if no cover. Release dates ReleaseDate One­to­many relationship of type ReleaseDate. Publishers Collection of Strings One­to­many relationship between publishers and the name of the game. Developer Collection of Strings One­to­many relationship between developers and the name of the game. Table 2.5. ReleaseDate table Field Data type Description OwnerId Long Identifier for the game. This field acts as a foreign key. platformName String Platform name under which game was released. releaseDate String Date when the game was released for this platform, in YYYY/MM/DD format. Table 2.6. Publisher table
  • 33. Field Data type Description OwnerId Long Identifier for the game. This field acts as a foreign key. publisherName String Publisher name. Table 2.7. Developer table Field Data type Description OwnerId Long Identifier for the game. This field acts as a foreign key. developer String Developer name. Figure 2.2. Gamer application entity relationship The entity­relationship schema in figure 2.2 shows that a game is composed of a title and a cover, is made by one­to­n (one­to­many) developers, is published by one or many publishers, and has zero or more release dates for each platform. Note There are other options that are a good fit for caching data for microservice
  • 34. architectures, such as Infinispan, Hazelcast, and Redis. They not only offer time­to­live (TTL) features, which makes the refresh logic much simpler, but also work in distributed (clustered) environments, which is typical in microservice architectures. For teaching purposes, in this book we use a SQL database. This approach is simple and uses a technology that you may be accustomed to. This also allows us to introduce an important feature: persistence testing of the ORM. On the server layer, the game service runs on the WildFly Swarm application server. An overall schema of this service is shown in figure 2.3. The persistence layer uses an H2 SQL database for storing and retrieving cached data for games. Finally, the service connects to the external site (IGDB.com) to obtain information for games that aren’t yet cached on the system. Figure 2.3. Game service overview WildFly Swarm WildFly Swarm (http://wildfly­swarm.io) offers an approach to packaging and running Java EE applications by generating an uber­JAR (java ­jar MyApp.jar), which packages the application with just enough of the server runtime to run. It also has built­in support for applications and frameworks such as Logstash, Netflix projects like Hystrix and Ribbon, and Red Hat projects like Keycloak and Hawkular. 2.3.2. The comments service
  • 35. 2.3.2. The comments service Build and package the comments service using the following code: cd ./comments ./gradlew war ­x test The comments service is an EE 7 application running on Apache TomEE. It’s responsible for managing comments for a specific game, as well as the game rating. A rating is a number between 1 (the lowest rating) and 5 (the highest rating). Notice that this feature isn’t provided by IGDB; it’s something you’ll add to the portal to make it more participatory. This service provides two endpoints: One adding a comment and a game rating A second that returns all the comments that have been written for a game, along with the average game rating The persistence layer for this service uses a document­oriented NoSQL database for storing all the data required by the service. We chose the MongoDB NoSQL database specifically due to its out­of­the­box aggregation framework. It’s a perfect solution for calculating the average rating for a given game. Note Similar logic could be implemented using a traditional SQL database, but nowadays it’s not uncommon to use a NoSQL database due to its better performance in certain circumstances. This service uses a NoSQL database to showcase the example. MongoDB MongoDB is a document­oriented NoSQL database. Instead of using a relational database structure, MongoDB stores JSON­like documents with dynamic schemas in collections. Documents that have a similar purpose are stored in the same collection. You can think of a collection as being equivalent to an RDBMS table, but without forcing a schema. In addition to storing documents, MongoDB provides features like indexing, replication, load balancing with horizontal shards, and an aggregation framework.
  • 36. MongoDB structures documents into collections. For the comments service, this collection is named comments. Each document that represents a comment has a schema like the following and contains the game’s ID, the comment itself, and the game’s rating (see figure 2.4): { "gameId": 1234, "comment": "This game is awesome", "rate": 3 } Figure 2.4. Collection of comments An overall schema of the comments service is shown in figure 2.5. On the server layer, it runs on the Apache TomEE application server (http://tomee.apache.org); and for the persistence layer, it uses the MongoDB NoSQL database for storing and retrieving comments associated with games. Figure 2.5. Comments service overview
  • 37. Apache TomEE Apache TomEE (http://tomee.apache.org), pronounced “Tommy,” is an all­Apache Java EE 6 Web Profile–certified and EE 7–enabled stack where Apache Tomcat is top dog. Apache TomEE is assembled from a vanilla Apache Tomcat zip file. Starting with Apache Tomcat, TomEE adds its JARs and zips up the rest. The result is Tomcat with added EE features—hence, the name TomEE. 2.3.3. The video service Build the video service using the following code: cd video ./gradlew build ­x test The video service is a Spring Boot application that’s responsible for retrieving the three most prominent videos related to a given game. Notice that this feature isn’t provided by IGDB; it’s something you’ll add to the portal to make it more attractive to end users. Obviously, this service isn’t going to reinvent the wheel by creating a new video­ sharing/­streaming site, so it uses YouTube to retrieve videos. YouTube YouTube is a global video­sharing website. You can add YouTube functionality to any
  • 38. site and even search for content. The YouTube Data API is the REST API that YouTube provides to users to connect to its system and execute operations like uploading videos, modifying videos, and searching for videos that match specific terms. See the book’s appendix for information about how to use the YouTube Data API. This service provides a single endpoint, which returns the links of the three most prominent videos for the specified game. This microservice has no persistence layer in the sense of long­lived data stored in the system. For this microservice, a NoSQL in­memory database of key­value pairs is used for caching search results from YouTube. When you’re caching distributed data where optional durability is required, key­value databases are the best choice, because they fit this requirement perfectly. With this approach, you save time, because an external network hit is more expensive than an internal one. You also save on the hits quota allotted by the YouTube Data API. In the video service, the key­value database used as a caching system is the Redis database. Redis Redis is an in­memory data­structure store that can be used as a database, cache system, or message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, HyperLogLogs, and geospatial indexes with radius queries. Redis offers clustering capabilities, master­slave replication, and transactions, with extremely good performance when not persisting data. The Redis structure used for this microservice is a list. This basic structure holds a list of string values for a given key with an optional TTL. In this case, the key is the game ID, and the value of each element of the list is a URL of the video associated with the game. As you can see in the schema shown in figure 2.6, the Redis structure stores a game ID and a list of three YouTube URLs. Spring Boot
  • 39. Spring Boot (http://projects.spring.io/spring­boot) makes it easy to create standalone, production­grade, Spring­based applications that you can “just run.” It follows the uber(fat)­JAR approach by packaging an application into a single JAR file, which contains the runtime (embedded server plus application) and a Main class to run it. It integrates well with other products in the Spring ecosystem, like Spring Data and Spring Security. Figure 2.6. Video URLs cached in Redis An overall schema of this service is shown in figure 2.7. You can see that the video service is a Spring Boot application, and the cache layer it uses is Redis. The service connects to the external site (youtube.com) to get video links for a specific game. Figure 2.7. Video service 2.3.4. The aggregator service Build and package the aggregator service using the following code: cd aggregator ./gradlew war ­x test
  • 40. This service is an EE 7 application that’s responsible for creating calls to the game and comments services, merging the results of both calls into a single document, and returning this document to the caller. This service provides three endpoints: One for adding a comment and a game rating A second that returns all the games that have a specified name A third that returns all the data related to a specified game, all user comments and ratings, and the three most important videos for the game The overall schema of the aggregator service is shown in figure 2.8. It has no persistence layer. The service runs inside the Apache Tomcat server and connects to all other services. Apache Tomcat The Apache Tomcat server is an open source implementation of the Java Servlet, JavaServer Pages, Java Expression Language, and Java WebSocket technologies. Figure 2.8. Game aggregator service relations to other services 2.3.5. Overall architecture
  • 41. 2.3.5. Overall architecture In summary, the Gamer app is made up of three services. Each of these services is deployed in a different platform, from the light application server Apache TomEE to a WildFly Swarm uber­JAR. Two different kinds of database engines are used for the persistence layer: H2, a traditional SQL database, and MongoDB, which belongs to the family of NoSQL databases. This is a broad range of technologies. We chose to use these various technologies specifically to broaden the scope of this book for the purposes of illustration. In the real world, your applications are likely to be founded on technologies that are more similar to each other. But, as mentioned previously, it’s not uncommon for different teams to work on different microservices. The overall schema of the Gamer app can be seen in the architecture diagram in figure 2.9. It’s important to note in the schema diagram how all the pieces are connected to compose a fully functional, microservice­based application. Figure 2.9. Architecture diagram of our project 2.4. APPLICATION DESIGN PATTERNS In previous sections, you’ve read about the Gamer app from a high­level perspective,
  • 42. and we’ve been paying a lot of attention to the requirements of the application from a business perspective. In the following sections, we’ll dig down into the technical side of the application. 2.4.1. Anatomy The Gamer app follows the microservices architecture by applying the Single Responsibility Principle (SRP) at an architectural level, making each service independent in terms of deployment, technology, and language. In summary, each microservice is structured following the schema shown in figure 2.10. Let’s see how each piece is implemented in the Gamer app. Figure 2.10. Detailed microservice structure The resource component The resource component is a thin layer of the application that acts as a mapper between incoming messages (typically JSON documents) and the business logic in the domain component. It also provides a response in accordance with the outcome produced by the business logic, using the desired protocol. In Java EE, this component is typically implemented using the Java API for RESTful Web Services (JAX­RS), which provides support for creating web services following the REST architectural pattern. An example of a resource component is coded in the
  • 43. comments service (code/comments/src/main/java/book/comments/boundary/CommentsResource.java). Listing 2.1. Resource component @Path("/comments") 1 @Singleton @Lock(LockType.READ) public class CommentsResource { @Inject private Comments comments; @Inject private DocumentToJsonObject transformer; @GET 2 @Path("/{gameId}") @Produces(MediaType.APPLICATION_JSON) 3 public Response getCommentsOfGivenGame(@PathParam("gameId") final Integer gameId) { 4 final Optional<Document>; commentsAndRating = comments .getCommentsAndRating(gameId); final JsonObject json = transformer.transform (commentsAndRating.orElse(new Document())); return Response.ok(json).build(); 5 } } 1 Sets the relative path for a class or method 2 Indicates that the method services the HTTP GET request type 3 Sets the response MIME type 4 Binds the parameter to a path segment 5 Returns the content with the HTTP response code OK (200) Request processing occurs by default in a synchronous fashion; this means a client request is processed by a single container I/O thread from start to finish. This blocking approach is fine for business logic that takes only a short time to execute. But for long­running tasks, the container thread will remain occupied until the task has been completed. This can have a significant impact on the server’s throughput, because new connections can remain blocked longer than expected while waiting for the backlog queue to be processed.
  • 44. To resolve this problem, JAX­RS has an asynchronous model. This enables the container thread to be released to accept a new connection before the client connection is closed. The lengthy task runs in another thread, and the container I/O thread can be used by another connection that’s waiting in the backlog queue. An example of an asynchronous resource component is coded in the game service (code/game/src/main/java/book/games/boundary/GamesResource.java), because connections to external resources can take a considerable amount of time to complete. Listing 2.2. Asynchronous resource component @Path("/") @javax.ejb.Singleton 1 @Lock(LockType.READ) public class GamesResource { @Inject GamesService gamesService; @Inject 2 ExecutorServiceProducer managedExecutorService; @GET @Produces(MediaType.APPLICATION_JSON) @javax.ejb.Asynchronous 3 public void searchGames(@Suspended final AsyncResponse response, 4 @NotNull @QueryParam("query") final String query) { response.setTimeoutHandler(asyncResponse ­>; asyncResponse .resume(Response.status(Response.Status .SERVICE_UNAVAILABLE).entity("TIME OUT !") .build())); response.setTimeout(15, TimeUnit.SECONDS); managedExecutorService.getManagedExecutorService().submit( () ­>; { 5 try { final Collector<JsonObject, ?, JsonArrayBuilder>; jsonCollector = Collector.of (Json::createArrayBuilder, JsonArrayBuilder::add, (left, right) ­>; { left.add(right); return left; }); final List<SearchResult>; searchResults =
  • 45. gamesService.searchGames(query); final JsonArrayBuilder mappedGames = searchResults .stream().map(SearchResult::convertToJson) .collect(jsonCollector); final Response.ResponseBuilder ok = Response.ok (mappedGames.build()); response.resume(ok.build()); 6 } catch (final Throwable e) { response.resume(e); 7 } }); } } 1 Resource is marked as Singleton EJB so the endpoint becomes transactional 2 Injects an executor service provided by the container 3 Designates a method as asynchronous. Valid only if it’s an EJB. 4 Instructs the JAX­RS runtime that this method is asynchronous and injects an AsyncResponse 5 Executes logic in a different thread 6 When the result is ready, the connection is resumed. 7 In case of an error, communication should also be resumed. For Spring applications, a resource is implemented using the Spring Web model­view­ controller (MVC) framework. This framework is built around the DispatcherServlet class and dispatches requests to configured handlers for executing business logic. An example of a resource written for the Spring Web MVC framework is coded in the video service (code/video/src/main/java/book/video/boundary/VideosResource.java). Listing 2.3. Spring resource package book.video.boundary; import book.video.controller.VideoServiceController; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping;
  • 46. import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @CrossOrigin(origins = {"http://localhost:8080", "http://localhost:8181", "http://localhost:8282", "http://localhost:8383"}) @RestController 1 public class VideosResource { @Autowired 2 VideoServiceController videoServiceController; @RequestMapping(value = "/", produces = "application/json") 3 public ResponseEntity<List<String>;>; getVideos( @RequestParam ("videoId") final long videoId, @RequestParam("gameName") final String gameName) { final List<String>; linksFromGame = videoServiceController .getLinksFromGame(Long.toString(videoId), gameName); return ResponseEntity.ok(linksFromGame); } } 1 The resource is marked as a Spring Rest controller. 2 Injects video­service logic 3 Configures the endpoint method Domain model A domain model is a representation or abstraction of real­world concepts belonging to the domain that need to be modeled in software. Each object of the domain incorporates both the data and the behavior of the object. In Java EE and Spring applications, if the domain is to be persisted to a SQL database, then the domain is annotated with Java Persistence API (JPA) annotations. We’ll discuss JPA in depth in chapters 4 and 5 . An example is found in the game service (code/game/src/main/java/book/games/entity/Game.java), where the domain model is Game. Listing 2.4. Domain model
  • 47. @Entity public class Game implements Serializable { @Id @Column(name = "id", updatable = false, nullable = false) private Long id; @Version @Column(name = "version") private int version; @Column 1 private String title; @Column private String cover; @ElementCollection @CollectionTable(name = "ReleaseDate", joinColumns = @JoinColumn(name = "OwnerId")) private List<ReleaseDate>; releaseDates = new ArrayList<>;(); @ElementCollection @CollectionTable(name = "Publisher", joinColumns = @JoinColumn (name = "OwnerId")) private List<String>; publishers = new ArrayList<>;(); @ElementCollection @CollectionTable(name = "Developer", joinColumns = @JoinColumn (name = "OwnerId")) private List<String>; developers = new ArrayList<>;(); public JsonObject convertToJson() { 2 final JsonArrayBuilder developers = Json.createArrayBuilder(); this.getDevelopers().forEach(developers::add); final JsonArrayBuilder publishers = Json.createArrayBuilder(); this.getPublishers().forEach(publishers::add); final JsonArrayBuilder releaseDates = Json .createArrayBuilder(); this.getReleaseDates().forEach(releaseDate ­>; { final String platform = releaseDate.getPlatformName(); final String date = releaseDate.getReleaseDate().format (DateTimeFormatter.ISO_DATE); releaseDates.add(Json.createObjectBuilder().add ("platform", platform).add("release_date", date)); }); return Json.createObjectBuilder().add("id", this.getId()) .add("title", this.getTitle()).add("cover", this .getCover()).add("developers", developers) .add("publishers", publishers).add("release_dates",
  • 48. releaseDates).build(); } } 1 Domain objects have fields that describe their properties in the system. 2 Object­manipulation methods should reside within the object. Service layer The services in the service layer are responsible for coordinating the various domain activities and interactions with other subsystems. For example, these services handle database interactions through the persistence component and call external services through the remote­resource component. In Java EE and Spring, this layer is usually implemented as a simple Java class, which is annotated in order to be eligible for injection either by context dependency injection (CDI), or autowiring in Spring components. Services should be injectable in any element that makes up the microservice. One example of a Java EE service can be found in the game service (code/game/src/main/java/book/games/control/GamesService.java). This service is responsible for checking if a game is cached in the Gamer local database, or if it must first be retrieved from the IGDB API. Listing 2.5. Java EE service @Dependent 1 public class GamesService { @EJB 2 Games games; @EJB IgdbGateway igdbGateway; public Game searchGameById(final long gameId) throws IOException { final Optional<Game>; foundGame = games.findGameById(gameId); 3 if (isGameInSiteDatabase(foundGame)) { return foundGame.get(); } else { final JsonArray jsonByGameId = igdbGateway .searchGameById(gameId); 4 final Game game = Game.fromJson(jsonByGameId); games.create(game); return game;
  • 49. } } } 1 Sets this class eligible for a CDI container as Dependent scoped 2 Other elements can be injected in a service. 3 Finds a game in the database 4 If the game isn’t found, gets it from IGDB A Spring service example can be found in the video service (code/video/src/main/java/book/video/boundary/YouTubeVideos.java). Listing 2.6. Spring service package book.video.boundary; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.util.List; @Service public class YouTubeVideos { @Autowired StringRedisTemplate redisTemplate; public void createYouTubeLinks(final String gameId, final List<String>; youtubeLinks) { final ListOperations<String, String>; stringStringListOperations = redisTemplate .opsForList(); stringStringListOperations.leftPushAll(gameId, youtubeLinks); } public boolean isGameInserted(final String gameId) { final ListOperations<String, String>; stringStringListOperations = redisTemplate .opsForList(); return stringStringListOperations.size(gameId) >; 0; } public List<String>; getYouTubeLinks(final String gameId) { final ListOperations<String, String>; stringStringListOperations = redisTemplate
  • 50. .opsForList(); final Long size = stringStringListOperations.size(gameId); return stringStringListOperations.range(gameId, 0, size); } } Repositories Repositories act on collections of domain entities and generally act as entry points or bridges to the persistence­component backend. Tip If you’re only going to manage a single entity, we don’t recommend adding a repository layer, because it would add unnecessary overhead. There’s also no need to pass objects through layers that never interact with them. For educational purposes, we’ve implemented a simple repository layer that demonstrates how to best test the class in a real­world scenario. When using a SQL database over JPA in a Java EE container, you should use Enterprise Java Beans (EJBs), because they provide transactional awareness, concurrency management, and security out of the box. An example repository layer can be found in the game service (code/game/src/main/java/book/games/boundary/Games.java). Listing 2.7. Repository layer @Stateless 1 public class Games { @PersistenceContext 2 EntityManager em; public Long create(final Game request) { final Game game = em.merge(request); 3 return game.getId(); } public Optional<Game>; findGameById(final Long gameId) { Optional<Game>; g = Optional.ofNullable(em.find(Game.class, gameId));
  • 51. if (g.isPresent()) { Game game = g.get(); game.getReleaseDates().size(); game.getPublishers().size(); game.getDevelopers().size(); em.detach(game); } return g; } } 1 EJBs ensure that classes are transaction aware by default. 2 Injects the EntityManager for database operations 3 Creates a new game When you use Spring, repositories are usually written to use the Spring Data project. This provides a familiar, consistent, Spring­based programming model for data access to relational and non­relational data stores, as well as to map­reduce frameworks and cloud­based data services. An example of a repository utilizing Spring Data can be found in the video service code for accessing Redis. Data mappers and object-relational mapping Just about all microservices need to persist some kind of data to persistent storage. In Java EE, when the persistence backend is a SQL database, the JPA specification is used through an object­relational mapping (ORM) tool. ORM is a technique for converting classes of object­oriented programming (OOP) languages into relational tables of relational database systems (RDBSs). Tip Some vendors also offer object mapping to NoSQL databases, but this feature isn’t in the specification. A JPA data­mapping example that demonstrates this capability can be seen in the game service (code/game/src/main/java/book/games/entity/Game.java). Listing 2.8. Data mapping
  • 52. @Entity public class Game implements Serializable { @Id @Column(name = "id", updatable = false, nullable = false) private Long id; @Version @Column(name = "version") private int version; @Column 1 private String title; @Column private String cover; @ElementCollection @CollectionTable(name = "ReleaseDate", joinColumns = @JoinColumn(name = "OwnerId")) private List<ReleaseDate>; releaseDates = new ArrayList<>;(); @ElementCollection @CollectionTable(name = "Publisher", joinColumns = @JoinColumn (name = "OwnerId")) private List<String>; publishers = new ArrayList<>;(); @ElementCollection @CollectionTable(name = "Developer", joinColumns = @JoinColumn (name = "OwnerId")) private List<String>; developers = new ArrayList<>;(); } 1 Object properties are mapped to relational table elements. Gateways and the HTTP client When a service collaborates with one or more microservices, logic must be implemented to communicate with these external services. A gateway encapsulates all the logic for connecting to a remote service and takes care of the underlying protocol and marshalling/unmarshalling objects to and from domain objects. REST architectures generally use the RESTful­web­services approach, so a gateway will more often than not use an HTTP client to connect to the external service. In Java EE, the JAX­RS specification provides client classes for consuming RESTful web services. Spring provides a simple but powerful class called RestTemplate, which provides methods for consuming other REST services. An example of a gateway that communicates with another microservice can be found in the aggregator service (code/aggregator/src/main/java/book/aggr/GamesGateway.java). Listing 2.9. Gateway
  • 53. Listing 2.9. Gateway public class GamesGateway { private final Client client; private final WebTarget games; private final String gamesHost; public GamesGateway() { this.client = ClientBuilder.newClient(); this.gamesHost = Optional.ofNullable(System.getenv ("GAMES_SERVICE_URL")).orElse(Optional.ofNullable (System.getProperty("GAMES_SERVICE_URL")).orElse ("http://localhost:8181/")); this.games = this.client.target(gamesHost); 1 } public Future<JsonObject>; getGameFromGamesService(final long gameId) { return this.games.path("{gameId}").resolveTemplate ("gameId", gameId) 2 .register(JsonStructureBodyReader.class) 3 .request(MediaType.APPLICATION_JSON).async() 4 .get(JsonObject.class); } } 1 Creates a client connection to a given server 2 Defines the endpoint URL 3 Registers the unmarshaller 4 Usually, aggregators want to execute calls in asynchronous mode. In this section, we’ve introduced you to the layers of a microservice. Let’s now see how to bring each of these elements into the Java space. 2.4.2. ECB pattern Each microservice developed for the Gamer app follows the entity control boundary (ECB) pattern. ECB is a variant of the well­known MVC pattern, but unlike MVC, it’s responsible not only for dealing with user interfaces, but also for applications (in our case, microservices) that don’t have a UI. The ECB pattern is composed of three elements (or key perspectives): entity, control,
  • 54. and boundary. Each element of a microservice can be assembled into one of these three perspectives: Entity—An object that represents a domain model. It primarily contains the data (attributes) required by the domain, but also performs behavior operations related to the entity, such as validating data and performing business operations. Control—An object that acts as the mediator between boundaries and entities. It manages the end­to­end behavior of a scenario. Boundary—An object that lies on the border of the system. Some boundary objects might be responsible for the frontend of the system: for example, REST endpoints. Others might be responsible for the backend, managing communications to external elements such as databases or other services, for example. Figure 2.11 shows how these elements fit together. Figure 2.11. ECB pattern The three elements can have certain appropriate interactions; others should not occur. The relationships between the entity, control, and boundary objects can be summarized as follows: An element can communicate with other elements of the same kind. A control can communicate with entity and boundary elements. Boundary and entity elements shouldn’t communicate directly. Table 2.8 illustrates these relations. Table 2.8. Communication between entity, control, and boundary objects Entity Boundary Control Entity X X Boundary X X
  • 55. Random documents with unrelated content Scribd suggests to you:
  • 56. 179 «¡Padre Júpiter! Haz que le caiga la suerte á Ayax, al hijo de Tideo, ó al mismo rey de Micenas, rica en oro.» 181 Así decían. Néstor, caballero gerenio, meneaba el casco, hasta que por fin saltó la tarja que ellos querían, la de Ayax. Un heraldo llevóla por el concurso y, empezando por la derecha, la enseñaba á los próceres aqueos, quienes, al no reconocerla, negaban que fuese la suya; pero cuando llegó al que la había marcado y echado en el casco, al ilustre Ayax, éste tendió la mano, y aquel se detuvo y le entregó la contraseña. El héroe la reconoció, con gran júbilo de su corazón, y tirándola al suelo, á sus pies, exclamó: 191 «¡Oh amigos! Mi tarja es, y me alegro en el alma porque espero vencer al divino Héctor. ¡Ea! Mientras visto la bélica armadura, orad al soberano Jove Saturnio, mentalmente, para que no lo oigan los teucros; ó en alta voz, pues á nadie tememos. No habrá quien, valiéndose de la fuerza ó de la astucia, me ponga en fuga contra mi voluntad; porque no creo que naciera y me criara en Salamina, tan inhábil para la lucha.» 200 Tales fueron sus palabras. Ellos oraron al soberano Jove Saturnio, y algunos dijeron mirando al anchuroso cielo: 202 «¡Padre Júpiter, que reinas desde el Ida, gloriosísimo, máximo! Concédele á Ayax la victoria y un brillante triunfo; y si amas también á Héctor y por él te interesas, dales á entrambos igual fuerza y gloria.» 206 Así hablaban. Púsose Ayax la armadura de luciente bronce; y vestidas las armas, marchó tan animoso como el terrible Marte cuando se encamina al combate de los hombres á quienes el Saturnio hace venir á las manos por una roedora discordia. Tan terrible se levantó Ayax, antemural de los aqueos, que sonreía con torva faz, andaba á paso largo y blandía enorme lanza. Los argivos se regocijaron grandemente, así que le vieron, y un violento temblor se apoderó de los teucros; al mismo Héctor palpitóle el corazón en el pecho; pero ya no podía manifestar temor ni retirarse á su ejército, porque de él había partido la provocación. Ayax se le acercó con su escudo como una torre, broncíneo, de siete pieles de buey, que en otro tiempo le hiciera Tiquio, el cual habitaba en Hila y era el mejor É
  • 57. de los curtidores. Éste formó el versátil escudo con siete pieles de corpulentos bueyes y puso encima, como octava capa, una lámina de bronce. Ayax Telamonio paróse, con la rodela al pecho, muy cerca de Héctor; y amenazándole, dijo: 226 «¡Héctor! Ahora sabrás claramente, de solo á solo, cuáles adalides pueden presentar los dánaos, aun prescindiendo de Aquiles que destruye los escuadrones y tiene el ánimo de un león. Mas el héroe, enojado con Agamenón, pastor de hombres, permanece en las corvas naves, que atraviesan el ponto, y somos muchos los capaces de pelear contigo. Pero empiece ya la lucha y el combate.» 233 Respondióle el gran Héctor, de tremolante casco: «¡Ayax Telamonio, de jovial linaje, príncipe de hombres! No me tientes cual si fuera un débil niño ó una mujer que no conoce las cosas de la guerra. Versado estoy en los combates y en las matanzas de hombres; sé mover á diestro y á siniestro la seca piel de buey que llevo para luchar denodadamente, sé lanzarme á la pelea cuando en prestos carros se batalla, y sé deleitar á Marte en el cruel estadio de la guerra. Pero á ti, siendo cual eres, no quiero herirte con alevosía, sino cara á cara, si conseguirlo puedo.»
  • 58. Ayax fué al encuentro de Héctor, con su escudo como una torre (Canto VII, verso 219.)
  • 59. 244 Dijo, y blandiendo la enorme lanza, arrojóla y atravesó el bronce que cubría como octava capa el gran escudo de Ayax, formado por siete boyunos cueros: la indomable punta horadó seis de éstos y en el séptimo quedó detenida. Ayax, descendiente de Júpiter, tiró á su vez un bote en el escudo liso del Priámida, y el asta, pasando por la tersa rodela, se hundió en la labrada coraza y rasgó la túnica sobre el ijar; inclinóse el héroe, y evitó la negra muerte. Y arrancando ambos las luengas lanzas de los escudos, acometiéronse como carniceros leones ó puercos monteses cuya fuerza es inmensa. El Priámida hirió con la lanza el centro del escudo de Ayax, y el bronce no pudo romperlo porque la punta se torció. Ayax, arremetiendo, clavó la suya en la rodela de aquél, é hizo vacilar al héroe cuando se disponía para el ataque; la punta abrióse camino hasta el cuello de Héctor, y en seguida brotó la negra sangre. Mas no por esto cesó de combatir Héctor, de tremolante casco, sino que, volviéndose, cogió con su robusta mano un pedrejón negro y erizado de puntas que había en el campo; lo tiró, acertó á dar en el bollón central del gran escudo de Ayax, de siete boyunas pieles, é hizo resonar el bronce de la rodela. Ayax entonces, tomando una piedra mucho mayor, la despidió haciéndola voltear con una fuerza inmensa. La piedra torció el borde inferior del hectóreo escudo, cual pudiera hacerlo una muela de molino, y chocando con las rodillas de Héctor le tumbó de espaldas, asido á la rodela; pero Apolo en seguida le puso en pie. Y ya se hubieran atacado de cerca con las espadas, si no hubiesen acudido dos heraldos, mensajeros de Júpiter y de los hombres, que llegaron respectivamente del campo de los teucros y del de los aqueos, de broncíneas lorigas: Taltibio é Ideo, prudentes ambos. Éstos interpusieron sus cetros entre los campeones, é Ideo, hábil en dar sabios consejos, pronunció estas palabras: 279 «¡Hijos queridos! No peleéis ni combatáis más; á entrambos os ama Júpiter, que amontona las nubes, y ambos sois belicosos. Esto lo sabemos todos. Pero la noche comienza ya, y será bueno obedecerla.» 283 Respondióle Ayax Telamonio: «¡Ideo! Ordenad á Héctor que lo disponga, pues fué él quien retó á los más valientes. Sea el
  • 60. primero en desistir; que yo obedeceré, si él lo hiciere.» 287 Díjole el gran Héctor, de tremolante casco: «¡Ayax! Puesto que los dioses te han dado corpulencia, valor y cordura, y en el manejo de la lanza descuellas entre los aqueos, suspendamos por hoy el combate y la lucha, y otro día volveremos á pelear hasta que una deidad nos separe, después de otorgar la victoria á quien quisiere. La noche comienza ya, y será bueno obedecerla. Así tú regocijarás, en las naves, á todos los aqueos y especialmente á tus amigos y compañeros; y yo alegraré, en la gran ciudad del rey Príamo, á los troyanos y á las troyanas, de rozagantes peplos, que habrán ido á los sagrados templos á orar por mí. ¡Ea! Hagámonos magníficos regalos, para que digan aqueos y teucros: Combatieron con roedor encono, y se separaron por la amistad unidos.» 303 Cuando esto hubo dicho, entregó á Ayax una espada guarnecida con argénteos clavos, ofreciéndosela con la vaina y el bien cortado ceñidor; y Ayax regaló á Héctor un vistoso tahalí teñido de púrpura. Separáronse luego, volviendo el uno á las tropas aqueas y el otro al ejército de los teucros. Éstos se alegraron al ver á Héctor vivo, y que regresaba incólume, libre de la fuerza y de las invictas manos de Ayax, cuando ya desesperaban de que se salvara; y le acompañaron á la ciudad. Por su parte, los aqueos, de hermosas grebas, llevaron á Ayax, ufano de la victoria, á la tienda del divino Agamenón. 313 Así que estuvieron en ella, Agamenón Atrida, rey de hombres, sacrificó al prepotente Saturnio un buey de cinco años. Tan pronto como lo hubieron desollado y preparado, lo descuartizaron hábilmente y cogiendo con pinchos los pedazos, los asaron con el cuidado debido y los retiraron del fuego. Terminada la faena y dispuesto el festín, comieron sin que nadie careciese de su respectiva porción; y el poderoso héroe Agamenón Atrida obsequió á Ayax con el ancho lomo. Cuando hubieron satisfecho el deseo de comer y de beber, el anciano Néstor, cuya opinión era considerada siempre como la mejor, comenzó á darles un consejo. Y arengándolos con benevolencia, así les dijo: 327 «¡Atrida y demás príncipes de los aqueos todos! Ya que han muerto tantos aquivos, de larga cabellera, cuya sangre esparció el
  • 61. cruel Marte por la ribera del Escamandro de límpida corriente y cuyas almas descendieron al Orco, conviene que suspendas los combates; y mañana, reunidos todos al comenzar del día, traeremos los cadáveres en carros tirados por bueyes y mulos, y los quemaremos cerca de los bajeles para llevar sus cenizas á los hijos de los difuntos cuando regresemos á la patria. Erijamos luego con tierra de la llanura, amontonada en torno de la pira, un túmulo común; edifiquemos á partir del mismo una muralla con altas torres que sea un reparo para las naves y para nosotros mismos; dejemos puertas, que se cierren con bien ajustadas tablas, para que pasen los carros, y cavemos al pie del muro un profundo foso, que detenga á los hombres y á los caballos si algún día no podemos resistir la acometida de los altivos teucros.» 344 Así habló, y los demás reyes aplaudieron. Reuniéronse los teucros en la acrópolis de Ilión, cerca del palacio de Príamo; y la junta fué agitada y turbulenta. El prudente Antenor comenzó á arengarles de esta manera: 348 «¡Oídme, troyanos, dárdanos y aliados, y os manifestaré lo que en el pecho mi corazón me dicta! Ea, restituyamos la argiva Helena con sus riquezas y que los Atridas se la lleven. Ahora combatimos después de quebrar la fe ofrecida en los juramentos, y no espero que alcancemos éxito alguno mientras no hagamos lo que propongo.» 354 Dijo, y se sentó. Levantóse el divino Alejandro, esposo de Helena, la de hermosa cabellera, y dirigiéndose á aquél pronunció estas aladas palabras: 357 «¡Antenor! No me place lo que propones, y podías haber pensado algo mejor. Si realmente hablas con seriedad, los mismos dioses te han hecho perder el juicio. Y á los troyanos, domadores de caballos, les diré lo siguiente: Paladinamente lo declaro, no devolveré la esposa; pero sí quiero dar cuantas riquezas traje de Argos y aun otras que añadiré de mi casa.» 365 Dijo, y se sentó. Levantóse Príamo Dardánida, consejero igual á los dioses, y les arengó con benevolencia diciendo: 368 «¡Oídme, troyanos, dárdanos y aliados, y os manifestaré lo que en el pecho mi corazón me dicta! Cenad en la ciudad, como
  • 62. siempre; acordaos de la guardia, y vigilad todos; al romper el alba vaya Ideo á las cóncavas naves, anuncie á los Atridas, Agamenón y Menelao, la proposición de Alejandro, por quien se suscitó la contienda, y hágales esta prudente consulta: Si quieren que se suspenda el horrísono combate para quemar los cadáveres, y luego volveremos á pelear hasta que una deidad nos separe y otorgue la victoria á quien le plazca.» 379 De esta suerte habló; ellos le escucharon y obedecieron, tomando la cena en el campo sin romper las filas; y apenas comenzó á alborear, encaminóse Ideo á las cóncavas naves y halló á los dánaos, ministros de Marte, reunidos en junta cerca del bajel de Agamenón. El heraldo de voz sonora, puesto en medio, les dijo: 385 «¡Atrida y demás príncipes de los aqueos todos! Mándanme Príamo y los ilustres troyanos que os participe, y ojalá os fuera acepta y grata, la proposición de Alejandro, por quien se suscitó la contienda. Ofrece dar cuantas riquezas trajo á Ilión en las cóncavas naves—¡así hubiese perecido antes!—y aun añadir otras de su casa; pero se niega á devolver la legítima esposa del glorioso Menelao, á pesar de que los troyanos se lo aconsejan. Me han ordenado también que os haga esta consulta: Si queréis que se suspenda el horrísono combate para quemar los cadáveres, y luego volveremos á pelear hasta que una deidad nos separe y otorgue la victoria á quien le plazca.» 398 Así habló. Todos enmudecieron y quedaron silenciosos. Pero al fin Diomedes, valiente en la pelea, dijo: 400 «No se acepten ni las riquezas de Alejandro, ni á Helena tampoco; pues es evidente, hasta para el más simple, que la ruina pende sobre los troyanos.» 403 Así se expresó; y todos los aqueos aplaudieron, admirados del discurso de Diomedes, domador de caballos. Y el rey Agamenón dijo entonces á Ideo: 406 «¡Ideo! Tú mismo oyes las palabras con que te responden los aqueos; ellas son de mi agrado. En cuanto á los cadáveres, no me opongo á que sean quemados, pues ha de ahorrarse toda dilación para satisfacer prontamente á los que murieron, entregando
  • 63. sus cuerpos á las llamas. Júpiter tonante, esposo de Juno, reciba el juramento.» 412 Dicho esto, alzó el cetro á todos los dioses; é Ideo regresó á la sagrada Troya, donde le esperaban, reunidos en junta, troyanos y dárdanos. El heraldo, puesto en medio, dijo la respuesta. En seguida dispusiéronse unos á recoger los cadáveres, y otros á ir por leña. Á su vez, los argivos salieron de las naves de numerosos bancos; unos, para recoger los cadáveres, y otros, para cortar leña. 421 Ya el sol hería con sus rayos los campos, subiendo al cielo desde la plácida corriente del profundo Océano, cuando aqueos y teucros se mezclaron unos con otros en la llanura. Difícil era reconocer á cada varón; pero lavaban con agua las manchas de sangre de los cadáveres y, derramando ardientes lágrimas, los subían á los carros. El gran Príamo no permitía que los teucros lloraran: éstos, en silencio y con el corazón afligido, hacinaron los cadáveres sobre la pira, los quemaron y volvieron á la sacra Ilión. Del mismo modo, los aqueos, de hermosas grebas, hacinaron los cadáveres sobre la pira, los quemaron y volvieron á las cóncavas naves. 433 Cuando aún no despuntaba la aurora, pero ya la luz del alba aparecía, un grupo escogido de aqueos se reunió en torno de la pira. Erigieron con tierra de la llanura un túmulo común; construyeron á partir del mismo una muralla con altas torres, que sirviese de reparo á las naves y á ellos mismos; dejaron puertas, que se cerraban con bien ajustadas tablas, para que pudieran pasarlos carros, y cavaron al pie del muro un gran foso profundo y ancho que defendieron con estacas. De tal suerte trabajaban los aqueos, de larga cabellera. 443 Los dioses, sentados á la vera de Júpiter fulminador, contemplaban la grande obra de los aqueos, de broncíneas lorigas; y Neptuno, que sacude la tierra, empezó á decirles: 446 «¡Padre Júpiter! ¿Cuál de los mortales de la vasta tierra consultará con los dioses sus pensamientos y proyectos? ¿No ves que los aqueos, de larga cabellera, han construído delante de las naves un muro con su foso, sin ofrecer á los dioses hecatombes perfectas? La fama de este muro se extenderá tanto como la luz de la aurora; y se echará en olvido el que labramos Febo Apolo y yo,
  • 64. cuando con gran fatiga construímos la ciudad para el héroe Laomedonte.» 454 Júpiter, que amontona las nubes, respondió indignado: «¡Oh dioses! ¡Tú, prepotente batidor de la tierra, qué palabras proferiste! Á un dios muy inferior en fuerza y ánimo podría asustarle tal pensamiento; pero no á ti, cuya fama se extenderá tanto como la luz de la aurora. Ea, cuando los aqueos, de larga cabellera, regresen en las naves á su patria, derriba el muro, arrójalo entero al mar, y enarena otra vez la espaciosa playa para que desaparezca la gran muralla aquiva.» 464 Así éstos conversaban. Á puesta del sol los aqueos tenían la obra acabada; inmolaron bueyes y se pusieron á cenar en las respectivas tiendas, cuando arribaron, procedentes de Lemnos, muchas naves cargadas de vino que enviaba Euneo, hijo de Hipsipile y de Jasón, pastor de hombres. El hijo de Jasón mandaba separadamente, para los Atridas Agamenón y Menelao, mil medidas de vino. Los aqueos, de larga cabellera, acudieron á las naves; compraron vino, unos con bronce, otros con luciente hierro, otros con pieles, otros con vacas y otros con esclavos; y prepararon un festín espléndido. Toda la noche los aquivos, de larga cabellera, disfrutaron del banquete, y lo mismo hicieron en la ciudad los troyanos y sus aliados. Toda la noche estuvo el próvido Júpiter meditando cómo les causaría males, hasta que por fin tronó de un modo horrible: el pálido temor se apoderó de todos, derramaron á tierra el vino de las copas, y nadie se atrevió á beber sin que antes hiciera libaciones al prepotente Saturnio. Después se acostaron y el don del sueño recibieron.
  • 65. Las Horas desuncen los corceles del carro en que iban Juno y Minerva CANTO VIII BATALLA INTERRUMPIDA 1 La Aurora, de azafranado velo, se esparcía por toda la tierra, cuando Júpiter, que se complace en lanzar rayos, reunió la junta de los dioses en la más alta de las muchas cumbres del Olimpo. Y así les habló, mientras ellos atentamente le escuchaban: 5 «¡Oídme todos, dioses y diosas, para que os manifieste lo que en el pecho mi corazón me dicta! Ninguno de vosotros, sea varón ó hembra, se atreva á transgredir mi mandato; antes bien, asentid todos, á fin de que cuanto antes lleve al cabo lo que me propongo. El dios que intente separarse de los demás y socorrer á los teucros ó á los dánaos, como yo le vea, volverá afrentosamente golpeado al Olimpo; ó cogiéndole, lo arrojaré al tenebroso Tártaro, muy lejos, en lo más profundo del báratro debajo de la tierra—sus puertas son de hierro, y el umbral, de bronce, y su profundidad desde el Orco como del cielo á la tierra—y conocerá en seguida cuánto aventaja mi poder al de las demás deidades. Y si queréis, haced esta prueba, oh dioses, para que os convenzáis. Suspended del cielo áurea cadena,
  • 66. asíos todos, dioses y diosas, de la misma, y no os será posible arrastrar del cielo á la tierra á Júpiter, árbitro supremo, por mucho que os fatiguéis; mas si yo me resolviese á tirar de aquélla, os levantaría con la tierra y el mar, ataría un cabo de la cadena en la cumbre del Olimpo, y todo quedaría en el aire. Tan superior soy á los dioses y á los hombres.» 28 Así habló; y todos callaron, asombrados de sus palabras, pues fué mucha la vehemencia con que se expresara. Al fin, Minerva, la diosa de los brillantes ojos, dijo: 31 «¡Padre nuestro, Saturnio, el más excelso de los soberanos! Bien sabemos que es incontrastable tu poder; pero tenemos lástima de los belicosos dánaos, que morirán, y se cumplirá su aciago destino. Nos abstendremos de intervenir en el combate, si nos lo mandas; pero sugeriremos á los argivos consejos saludables, á fin de que no perezcan todos, víctimas de tu cólera.» 38 Sonriéndose, le contestó Júpiter, que amontona las nubes: «Tranquilízate, Tritogenia, hija querida. No hablo con ánimo benigno, pero contigo quiero ser complaciente.» 41 Esto dicho, unció los corceles de pies de bronce y áureas crines, que volaban ligeros; vistió la dorada túnica, tomó el látigo de oro y fina labor, y subió al carro. Picó á los caballos para que arrancaran; y éstos, gozosos, emprendieron el vuelo entre la tierra y el estrellado cielo. Pronto llegó al Ida, abundante en fuentes y criador de fieras, al Gárgaro, donde tenía un bosque sagrado y un perfumado altar; allí el padre de los hombres y de los dioses detuvo los bridones, los desenganchó del carro y los cubrió de espesa niebla. Sentóse luego en la cima, ufano de su gloria, y se puso á contemplar la ciudad troyana y las naves aqueas. 53 Los aqueos, de larga cabellera, se desayunaron apresuradamente en las tiendas, y en seguida tomaron las armas. También los teucros se armaron dentro de la ciudad; y aunque eran menos, estaban dispuestos á combatir, obligados por la cruel necesidad de proteger á sus hijos y mujeres: abriéronse todas las puertas, salió el ejército de infantes y de los que peleaban en carros, y se produjo un gran tumulto.
  • 67. 60 Cuando los dos ejércitos llegaron á juntarse, chocaron entre sí los escudos, las lanzas y el valor de los guerreros armados de broncíneas corazas, y al aproximarse las abollonadas rodelas se produjo un gran tumulto. Allí se oían simultáneamente los lamentos de los moribundos y los gritos jactanciosos de los matadores, y la tierra manaba sangre. 66 Al amanecer y mientras iba aumentando la luz del sagrado día, los tiros alcanzaban por igual á unos y á otros, y los hombres caían. Cuando el sol hubo recorrido la mitad del cielo, el padre Jove tomó la balanza de oro, puso en ella dos suertes—la de los teucros, domadores de caballos, y la de los aqueos, de broncíneas lorigas— para saber á quiénes estaba reservada la dolorosa muerte; cogió por el medio la balanza, la desplegó y tuvo más peso el día fatal de los aqueos. La suerte de éstos bajó hasta llegar á la fértil tierra, mientras la de los teucros subía al cielo. Júpiter, entonces, truena fuerte desde el Ida y envía una ardiente centella á los aqueos, quienes, al verla, se pasman, sobrecogidos de pálido temor; ya no se atreven á permanecer en el campo ni Idomeneo, ni Agamenón, ni los dos Ayaces, ministros de Marte; y sólo se queda Néstor gerenio, protector de los aqueos, contra su voluntad, por tener malparado uno de los corceles, al cual el divino Alejandro, esposo de Helena, la de hermosa cabellera, flechara en lo alto de la cabeza, donde las crines empiezan á crecer y las heridas son mortales. El caballo, al sentir el dolor, se encabrita, y la flecha le penetra el cerebro; y revolcándose para sacudir el bronce, espanta á los demás caballos. Mientras el anciano se daba prisa á cortar con la espada las correas del caído corcel, vienen á través de la muchedumbre los veloces caballos de Héctor, tirando del carro en que iba tan audaz guerrero. Y el anciano perdiera allí la vida, si al punto no lo hubiese advertido Diomedes, valiente en la pelea; el cual, vociferando de un modo horrible, dijo á Ulises: 93 «¡Laertíada, de jovial linaje! ¡Ulises, fecundo en recursos! ¿Adónde huyes, confundido con la turba y volviendo la espalda como un cobarde? Que alguien no te clave la pica en el dorso, mientras pones los pies en polvorosa. Pero aguarda y apartaremos del anciano al feroz guerrero.»
  • 68. 97 Así dijo, y el paciente divino Ulises pasó sin oirle, corriendo hacia las cóncavas naves de los aqueos. El hijo de Tideo, aunque estaba solo, se abrió paso por las primeras filas; y deteniéndose ante el carro del viejo Nelida, pronunció estas aladas palabras: 102 «¡Oh anciano! Los guerreros mozos te acosan y te hallas sin fuerzas, abrumado por la molesta senectud; tu escudero tiene poco vigor y tus caballos son tardos. Sube á mi carro para que veas cuáles son los corceles de Tros que quité á Eneas, el que pone en fuga á sus enemigos, y cómo saben lo mismo perseguir acá y allá de la llanura, que huir ligeros. De los tuyos cuiden los servidores; y nosotros dirijamos éstos hacia los teucros, domadores de caballos, para que Héctor sepa con qué furia se mueve la lanza que mi mano blande.» 112 Dijo; y Néstor, caballero gerenio, no desobedeció. Encargáronse de sus yeguas los bravos escuderos Esténelo y Eurimedonte valeroso; y habiendo subido ambos héroes al carro de Diomedes, Néstor cogió las lustrosas riendas y avispó á los caballos, y pronto se hallaron cerca de Héctor, que cerró con ellos. El hijo de Tideo arrojóle un dardo, y si bien erró el tiro, hirió en el pecho cerca de la tetilla á Eniopeo, hijo del animoso Tebeo, que, como auriga, gobernaba las riendas: Eniopeo cayó del carro, cejaron los corceles y allí terminaron la vida y el valor del guerrero. Hondo pesar sintió el espíritu de Héctor por tal muerte; pero, aunque condolido del compañero, dejóle en el suelo y buscó otro auriga que fuese osado. Poco tiempo estuvieron los veloces caballos sin conductor, pues Héctor encontróse con el ardido Arqueptólemo Ifítida, y haciéndole subir, le puso las riendas en la mano. 130 Entonces gran estrago é irreparables males se hubieran producido y los teucros habrían sido encerrados en Ilión como corderos, si al punto no lo hubiese advertido el padre de los hombres y de los dioses. Tronando de un modo espantoso, despidió un ardiente rayo para que cayera en el suelo delante de los caballos de Diomedes; el azufre encendido produjo una terrible llama; los corceles, asustados, acurrucáronse debajo del carro; las lustrosas riendas cayeron de las manos de Néstor, y éste, con miedo en el corazón, dijo á Diomedes:
  • 69. 139 «¡Tidida! Tuerce la rienda á los solípedos caballos y huyamos. ¿No conoces que la protección de Júpiter ya no te acompaña? Hoy Jove Saturnio otorga á ése la victoria; otro día, si le place, nos la dará á nosotros. Ningún hombre, por fuerte que sea, puede impedir los propósitos de Júpiter, porque el dios es mucho más poderoso.» 145 Respondióle Diomedes, valiente en la pelea: «Sí, anciano, oportuno es cuanto acabas de decir, pero un terrible pesar me llega al corazón y al alma. Quizás diga Héctor, arengando á los teucros: El Tidida llegó á las naves, puesto en fuga por mi lanza. Así se jactará; y entonces ábraseme la vasta tierra.» 151 Replicóle Néstor, caballero gerenio: «¡Ay de mí! ¡Qué dijiste, hijo del belicoso Tideo! Si Héctor te llamare cobarde y débil, no le creerán ni los troyanos, ni los dardanios, ni las mujeres de los teucros magnánimos, escudados, cuyos esposos florecientes en el polvo derribaste.» 157 Dichas estas palabras, volvió la rienda á los solípedos caballos, y empezaron á huir por entre la turba. Los teucros y Héctor, promoviendo inmenso alboroto, hacían llover sobre ellos dañosos tiros. Y el gran Héctor, de tremolante casco, gritaba con voz recia: 161 «¡Tidida! Los dánaos, de ágiles corceles, te cedían la preferencia en el asiento y te obsequiaban con carne y copas de vino; mas ahora te despreciarán, porque te has vuelto como una mujer. Anda, tímida doncella; ya no escalarás nuestras torres, venciéndome á mí, ni te llevarás nuestras mujeres en las naves, porque antes te daré la muerte.» 167 Tal dijo. El Tidida estaba indeciso entre seguir huyendo ó torcer la rienda á los corceles y volver á pelear. Tres veces se le presentó la duda en la mente y en el corazón, y tres veces el próvido Júpiter tronó desde los montes ideos para anunciar á los teucros que suya sería en aquel combate la inconstante victoria. Y Héctor los animaba, diciendo á voz en grito: 173 «¡Troyanos, licios, dárdanos que cuerpo á cuerpo combatís! Sed hombres, amigos, y mostrad vuestro impetuoso valor. Conozco que el Saturnio me concede, benévolo, la victoria y gloria inmensa y
  • 70. envía la perdición á los dánaos; quienes, oh necios, construyeron esos muros débiles y despreciables que no podrán contener mi arrojo, pues los caballos salvarán fácilmente el cavado foso. Cuando llegue á las cóncavas naves, acordaos de traerme el voraz fuego, para que las incendie y mate junto á ellas á los argivos aturdidos por el humo.» 184 Dijo, y exhortó á sus caballos con estas palabras: «¡Janto, Podargo, Etón, divino Lampo! Ahora debéis pagarme el exquisito cuidado con que Andrómaca, hija del magnánimo Eetión, os ofrecía el regalado trigo y os mezclaba vinos para que pudieseis, bebiendo, satisfacer vuestro apetito; antes que á mí, que me glorío de ser su floreciente esposo. Seguid el alcance, esforzaos, para ver si nos apoderamos del escudo de Néstor, cuya fama llega hasta el cielo por ser de oro, sin exceptuar las abrazaderas, y le quitamos de los hombros á Diomedes, domador de caballos, la labrada coraza que Vulcano fabricara. Creo que si ambas cosas consiguiéramos, los aqueos se embarcarían esta misma noche en las veleras naves.» 198 Así habló, vanagloriándose. La veneranda Juno, indignada, se agitó en su trono, haciendo estremecer el espacioso Olimpo, y dijo al gran dios Neptuno: 201 «¡Oh dioses! ¡Prepotente Neptuno que bates la tierra! ¿Tu corazón no se compadece de los dánaos moribundos, que tantos y tan lindos presentes te llevaban á Hélice y á Egas? Decídete á darles la victoria. Si cuantos protegemos á los dánaos quisiéramos rechazar á los teucros y contener al longividente Júpiter, éste se aburriría sentado solo allá en el Ida.» 208 Respondióle muy indignado el poderoso dios que sacude la tierra: «¿Qué palabras proferiste, audaz Juno? Yo no quisiera que los demás dioses lucháramos con el Saturnio Jove, porque nos aventaja mucho en poder.» 212 Así éstos conversaban. Cuanto espacio había desde los bajeles al fosado muro, llenóse de carros y hombres escudados que allí acorraló Héctor Priámida, igual al impetuoso Marte, cuando Júpiter le dió gloria. Y el héroe hubiese pegado ardiente fuego á las naves bien proporcionadas, de no haber sugerido la venerable Juno á Agamenón que animara pronto á los aqueos. Fuése el Atrida hacia
  • 71. las tiendas y las naves aqueas con el grande purpúreo manto en el robusto brazo, y subió á la ingente nave negra de Ulises, que estaba en el centro, para que le oyeran por ambos lados hasta las tiendas de Ayax Telamonio y de Aquiles, los cuales habían puesto sus bajeles en los extremos porque confiaban en su valor y en la fuerza de sus brazos. Y con voz penetrante gritaba á los dánaos: 228 «¡Qué vergüenza, argivos, hombres sin dignidad, admirables sólo por la figura! ¿Qué es de la jactancia con que nos gloriábamos de ser valentísimos, y con que decíais presuntuosamente en Lemnos, comiendo abundante carne de bueyes de erguida cornamenta y bebiendo crateras de vino, que cada uno haría frente en la batalla á ciento y á doscientos troyanos? Ahora ni con uno podemos, con Héctor, que pronto pegará ardiente fuego á las naves. ¡Padre Júpiter! ¿Hiciste sufrir tamaña desgracia y privaste de una gloria tan grande á algún otro de los prepotentes reyes? Cuando vine, no pasé de largo en la nave de muchos bancos por ninguno de tus bellos altares, sino que en todos quemé grasa y muslos de buey, deseoso de asolar la bien murada Troya. Por tanto, oh Júpiter, cúmpleme este voto: déjanos escapar y librarnos de este peligro, y no permitas que los teucros maten á los argivos.» 245 Así se expresó. El padre, compadecido de verle derramar lágrimas, le concedió que su pueblo se salvara y no pereciese; y en seguida mandó un águila, la mejor de las aves agoreras, que tenía en las garras el hijuelo de una veloz cierva y lo dejó caer al pie del ara hermosa de Júpiter, donde los aqueos ofrecían sacrificios al dios, como autor de los presagios todos. Cuando los argivos vieron que el ave había sido enviada por Júpiter, arremetieron contra los teucros y sólo en combatir pensaron. 253 Entonces ninguno de los dánaos, aunque eran muchos, pudo gloriarse de haber revuelto sus veloces caballos para pasar el foso y resistir el ataque, antes que el Tidida. Fué éste el primero que mató á un guerrero teucro, á Agelao Fradmónida, que, subido en el carro, emprendía la fuga: hundióle la pica en la espalda, entre los hombros, y la punta salió por el pecho; Agelao cayó del carro y sus armas resonaron.
  • 72. 261 Siguieron á Diomedes, los Atridas Agamenón y Menelao; los Ayaces, revestidos de impetuoso valor; Idomeneo y su servidor Meriones, igual al homicida Marte; Eurípilo, hijo ilustre de Evemón; y en noveno lugar, Teucro, que, con el flexible arco en la mano, se escondía detrás del escudo de Ayax Telamonio. Éste levantaba la rodela; y Teucro, volviendo el rostro á todos lados, flechaba á un troyano que caía mortalmente herido, y al momento tornaba á refugiarse en Ayax (como un niño en su madre), quien le cubría otra vez con el refulgente escudo. 273 ¿Cuál fué el primero, cuál el último de los que entonces mató el eximio Teucro? Orsíloco el primero, Órmeno, Ofelestes, Détor, Cromio, Licofontes igual á un dios, Amopaón Poliemónida y Melanipo. Á tantos derribó sucesivamente al almo suelo. El rey de hombres Agamenón se holgó de ver que Teucro destruía las falanges troyanas, disparando el fuerte arco; y poniéndose á su lado, le dijo: 281 «¡Caro Teucro Telamonio, príncipe de hombres! Sigue tirando flechas, por si acaso llegas á ser la aurora de salvación de los dánaos y honras á tu padre Telamón, que te crió cuando eras niño y te educó en su casa, á pesar de tu condición de bastardo; ya que está lejos de aquí, cúbrele de gloria. Lo que voy á decir, se cumplirá: Si Júpiter, que lleva la égida, y Minerva me permiten destruir la bien edificada ciudad de Ilión, te pondré en la mano, como premio de honor únicamente inferior al mío, ó un trípode, ó dos corceles con su correspondiente carro, ó una mujer que comparta contigo el lecho.» 292 Respondióle el eximio Teucro: «¡Gloriosísimo Atrida! ¿Por qué me instigas cuando ya, solícito, hago lo que puedo? Desde que los rechazamos hacia Ilión mato hombres, valiéndome del arco. Ocho flechas de larga punta tiré, y todas se clavaron en el cuerpo de jóvenes llenos de marcial furor; pero no consigo herir á ese perro rabioso.» 300 Dijo; y apercibiendo el arco, envió otra flecha á Héctor con intención de herirle. Tampoco acertó; pero la saeta clavóse en el pecho del eximio Gorgitión, valeroso hijo de Príamo y de la bella Castianira, oriunda de Esima, cuyo cuerpo al de una diosa semejaba. Como en un jardín inclina la amapola su tallo, combándose al peso
  • 73. del fruto ó de los aguaceros primaverales; de semejante modo inclinó el guerrero la cabeza que el casco hacía ponderosa. 309 Teucro armó nuevamente el arco, envió otra saeta á Héctor, con ánimo de herirle, y también erró el tiro, por haberlo desviado Apolo; pero hirió en el pecho cerca de la tetilla á Arqueptólemo, osado auriga de Héctor, cuando se lanzaba á la pelea. Arqueptólemo cayó del carro, cejaron los corceles de pies ligeros, y allí terminaron la vida y el valor del guerrero. Hondo pesar sintió el espíritu de Héctor por tal muerte; pero, aunque condolido del compañero, dejóle y mandó á su propio hermano Cebrión, que se hallaba cerca, que tomara las riendas de los caballos. Oyóle Cebrión y no desobedeció. Héctor saltó del refulgente carro al suelo, y vociferando de un modo espantoso, cogió una piedra y encaminóse hacia Teucro con el propósito de herirle. Teucro, á su vez, sacó del carcaj una acerba flecha, y ya estiraba la cuerda del arco, cuando Héctor, de tremolante casco, acertó á darle con la áspera piedra cerca del hombro, donde la clavícula separa el cuello del pecho y las heridas son mortales, y le rompió el nervio: entorpecióse el brazo, Teucro cayó de hinojos y el arco se le fué de las manos. Ayax no abandonó al hermano caído en el suelo, sino que corriendo á defenderle, le resguardó con el escudo. Acudieron dos compañeros, Mecisteo, hijo de Equio, y el divino Alástor; y cogiendo á Teucro, que daba grandes suspiros, lo llevaron á las cóncavas naves. 335 El Olímpico volvió á excitar el valor de los teucros, los cuales hicieron arredrar á los aqueos en derechura al profundo foso. Héctor iba con los delanteros, haciendo gala de su fuerza. Como el perro que acosa con ágiles pies á un jabalí ó á un león, le muerde, ya los muslos, ya las nalgas, y observa si vuelve la cara; de igual modo perseguía Héctor á los aqueos de larga cabellera, matando al que se rezagaba, y ellos huían espantados. Cuando atravesaron la empalizada y el foso, muchos sucumbieron á manos de los teucros; los demás no pararon hasta las naves, y allí se animaban los unos á los otros, y con los brazos levantados oraban á todas las deidades. Héctor hacía girar por todas partes los corceles de hermosas crines; y sus ojos parecían los de la Gorgona ó los de Marte, peste de los hombres.
  • 74. 350 Juno, la diosa de los níveos brazos, al ver á los aqueos compadeciólos, y dirigió á Minerva estas aladas palabras: 352 «¡Oh dioses! ¡Hija de Júpiter, que lleva la égida! ¿No nos cuidaremos de socorrer, aunque tarde, á los dánaos moribundos? Perecerán, cumpliéndose su aciago destino, por el arrojo de un solo hombre, de Héctor Priámida, que se enfurece de intolerable modo y ha causado ya gran estrago.» 357 Respondióle Minerva, la diosa de los brillantes ojos: «Tiempo ha que ése hubiera perdido fuerza y vida, muerto en su misma patria por los aqueos; pero mi padre revuelve en su mente funestos propósitos, ¡cruel, siempre injusto, desbaratador de mis planes!, y no recuerda cuántas veces salvé á su hijo abrumado por los trabajos que Euristeo le impusiera. Hércules clamaba al cielo, llorando, y Júpiter me enviaba á socorrerle. Si mi sabia mente hubiese presentido lo de ahora, no hubiera escapado el hijo de Júpiter de las hondas corrientes de la Estigia, cuando aquél le mandó que fuera al Orco, de sólidas puertas, y sacara del Érebo el horrendo can de Plutón. Al presente Jove me aborrece y cumple los deseos de Tetis, que besó sus rodillas y le tocó la barba, suplicándole que honrase á Aquiles, asolador de ciudades. Día vendrá en que me llame nuevamente su amada hija, la de los brillantes ojos. Pero unce los solípedos corceles, mientras yo, entrando en el palacio de Júpiter, me armo para la guerra; quiero ver si el hijo de Príamo, Héctor, de tremolante casco, se alegrará cuando aparezcamos en el campo de la batalla. Alguno de los teucros, cayendo junto á las naves aqueas, saciará con su grasa y con su carne á los perros y á las aves.» 381 Dijo; y Juno, la diosa de los níveos brazos, no fué desobediente. La venerable diosa Juno, hija del gran Saturno, aprestó solícita los caballos de áureos jaeces. Y Minerva, hija de Júpiter, que lleva la égida, dejó caer al suelo el hermoso peplo bordado que ella misma tejiera y labrara con sus manos; vistió la loriga de Jove, que amontona las nubes, y se armó para la luctuosa guerra. Y subiendo al flamante carro, asió la lanza ponderosa, larga, fornida, con que la hija del prepotente padre destruye filas enteras de héroes cuando contra ellos monta en cólera. Juno picó con el látigo á los bridones, y abriéronse de propio impulso, rechinando, las
  • 75. puertas del cielo de que cuidan las Horas—á ellas está confiado el espacioso cielo y el Olimpo—para remover ó colocar delante la densa nube. Por allí, á través de las puertas, dirigieron aquellas deidades los corceles, dóciles al látigo. 397 El padre Júpiter, apenas las vió desde el Ida, se encendió en cólera; y al punto llamó á Iris, la de doradas alas, para que le sirviese de mensajera: 399 «¡Anda, ve, rápida Iris! Haz que se vuelvan y no les dejes llegar á mi presencia, porque ningún beneficio les reportará luchar conmigo. Lo que voy á decir, se cumplirá: Encojaréles los briosos corceles; las derribaré del carro, que romperé luego, y ni en diez años cumplidos sanarán de las heridas que les produzca el rayo, para que conozca la de los brillantes ojos que es con su padre contra quien combate. Con Juno no me irrito ni me encolerizo tanto, porque siempre ha solido oponerse á mis proyectos.» 409 De tal modo habló. Iris, la de los pies rápidos como el huracán, se levantó para llevar el mensaje; descendió de los montes ideos; y alcanzando á las diosas en la entrada del Olimpo, en valles abundoso, hizo que se detuviesen, y les transmitió la orden de Júpiter: 413 «¿Adónde corréis? ¿Por qué en vuestro pecho el corazón se enfurece? No consiente el Saturnio que se socorra á los argivos. Ved aquí lo que hará el hijo de Saturno, si cumple su amenaza: Os encojará los briosos caballos, os derribará del carro, que romperá luego, y ni en diez años cumplidos sanaréis de las heridas que os produzca el rayo; para que conozcas tú, la de los brillantes ojos, que es con tu padre contra quien combates. Con Juno no se irrita ni se encoleriza tanto, porque siempre ha solido oponerse á sus proyectos. Pero tú, temeraria, perra desvergonzada, si realmente te atrevieras á levantar contra Júpiter la formidable lanza...» 425 Cuando esto hubo dicho, fuése Iris, la de los pies ligeros; y Juno dirigió á Minerva estas palabras: 427 «¡Oh dioses! ¡Hija de Júpiter, que lleva la égida! Ya no permito que por los mortales peleemos con Jove. Mueran unos y vivan otros, cualesquiera que fueren; y aquél sea juez, como le
  • 76. Welcome to our website – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com