The customer Example Application
This section describes how to build and run the customer example
application. This application is a RESTful web service that uses JAXB to
perform the create, read, update, delete (CRUD) operations for a
specific entity.
The customer sample application is in the
_tut-install_/examples/jaxrs/customer/ directory. See
Chapter 2, "Using the Tutorial Examples,"
for basic information on building and running sample applications.
The following topics are addressed here:
Overview of the customer Example Application
The source files of this application are at
_tut-install_/examples/jaxrs/customer/src/main/java/. The application
has three parts.
-
The
CustomerandAddressentity classes. These classes model the data of the application and contain JAXB annotations. -
The
CustomerServiceresource class. This class contains JAX-RS resource methods that perform operations onCustomerinstances represented as XML or JSON data using JAXB. See The CustomerService Class for details. -
The
CustomerBeansession bean that acts as a backing bean for the web client.CustomerBeanuses the JAX-RS client API to call the methods ofCustomerService.
The customer example application shows you how to model your data
entities as Java classes with JAXB annotations.
The Customer and Address Entity Classes
The following class represents a customer’s address:
@Entity
@Table(name="CUSTOMER_ADDRESS")
@XmlRootElement(name="address")
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@XmlElement(required=true)
protected int number;
@XmlElement(required=true)
protected String street;
@XmlElement(required=true)
protected String city;
@XmlElement(required=true)
protected String province;
@XmlElement(required=true)
protected String zip;
@XmlElement(required=true)
protected String country;
public Address() { }
// Getter and setter methods
// ...
}
The @XmlRootElement(name="address") annotation maps this class to the
address XML element. The @XmlAccessorType(XmlAccessType.FIELD)
annotation specifies that all the fields of this class are bound to XML
by default. The @XmlElement(required=true) annotation specifies that
an element must be present in the XML representation.
The following class represents a customer:
@Entity
@Table(name="CUSTOMER_CUSTOMER")
@NamedQuery(
name="findAllCustomers",
query="SELECT c FROM Customer c " +
"ORDER BY c.id"
)
@XmlRootElement(name="customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@XmlAttribute(required=true)
protected int id;
@XmlElement(required=true)
protected String firstname;
@XmlElement(required=true)
protected String lastname;
@XmlElement(required=true)
@OneToOne
protected Address address;
@XmlElement(required=true)
protected String email;
@XmlElement (required=true)
protected String phone;
public Customer() {...}
// Getter and setter methods
// ...
}
The Customer class contains the same JAXB annotations as the previous
class, except for the @XmlAttribute(required=true) annotation, which
maps a property to an attribute of the XML element representing the
class.
The Customer class contains a property whose type is another entity,
the Address class. This mechanism allows you to define in Java code
the hierarchical relationships between entities without having to write
an .xsd file yourself.
JAXB generates the following XML schema definition for the two preceding classes:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="address" type="address"/>
<xs:element name="customer" type="customer"/>
<xs:complexType name="address">
<xs:sequence>
<xs:element name="id" type="xs:long" minOccurs="0"/>
<xs:element name="number" type="xs:int"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="province" type="xs:string"/>
<xs:element name="zip" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="customer">
<xs:sequence>
<xs:element name="firstname" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
<xs:element ref="address"/>
<xs:element name="email" type="xs:string"/>
<xs:element name="phone" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" type="xs:int" use="required"/>
</xs:complexType>
</xs:schema>
The CustomerService Class
The CustomerService class has a createCustomer method that creates a
customer resource based on the Customer class and returns a URI for
the new resource.
@Stateless
@Path("/Customer")
public class CustomerService {
public static final Logger logger =
Logger.getLogger(CustomerService.class.getCanonicalName());
@PersistenceContext
private EntityManager em;
private CriteriaBuilder cb;
@PostConstruct
private void init() {
cb = em.getCriteriaBuilder();
}
...
@POST
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response createCustomer(Customer customer) {
try {
long customerId = persist(customer);
return Response.created(URI.create("/" + customerId)).build();
} catch (Exception e) {
logger.log(Level.SEVERE,
"Error creating customer for customerId {0}. {1}",
new Object[]{customer.getId(), e.getMessage()});
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
}
...
private long persist(Customer customer) {
try {
Address address = customer.getAddress();
em.persist(address);
em.persist(customer);
} catch (Exception ex) {
logger.warning("Something went wrong when persisting the customer");
}
return customer.getId();
}
The response returned to the client has a URI to the newly created
resource. The return type is an entity body mapped from the property of
the response with the status code specified by the status property of
the response. The WebApplicationException is a RuntimeException that
is used to wrap the appropriate HTTP error status code, such as 404,
406, 415, or 500.
The @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
and @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
annotations set the request and response media types to use the
appropriate MIME client. These annotations can be applied to a resource
method, a resource class, or even an entity provider. If you do not use
these annotations, JAX-RS allows the use of any media type ("*/*").
The following code snippet shows the implementation of the getCustomer
and findbyId methods. The getCustomer method uses the @Produces
annotation and returns a Customer object, which is converted to an XML
or JSON representation depending on the Accept: header specified by
the client.
@GET
@Path("{id}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Customer getCustomer(@PathParam("id") String customerId) {
Customer customer = null;
try {
customer = findById(customerId);
} catch (Exception ex) {
logger.log(Level.SEVERE,
"Error calling findCustomer() for customerId {0}. {1}",
new Object[]{customerId, ex.getMessage()});
}
return customer;
}
...
private Customer findById(String customerId) {
Customer customer = null;
try {
customer = em.find(Customer.class, customerId);
return customer;
} catch (Exception ex) {
logger.log(Level.WARNING,
"Couldn't find customer with ID of {0}", customerId);
}
return customer;
}
Using the JAX-RS Client in the CustomerBean Classes
Use the JAX-RS Client API to write a client for the customer example
application.
The CustomerBean enterprise bean class calls the JAX-RS Client API to
test the CustomerService web service:
@Named
@Stateless
public class CustomerBean {
protected Client client;
private static final Logger logger =
Logger.getLogger(CustomerBean.class.getName());
@PostConstruct
private void init() {
client = ClientBuilder.newClient();
}
@PreDestroy
private void clean() {
client.close();
}
public String createCustomer(Customer customer) {
if (customer == null) {
logger.log(Level.WARNING, "customer is null.");
return "customerError";
}
String navigation;
Response response =
client.target("http://localhost:8080/customer/webapi/Customer")
.request(MediaType.APPLICATION_XML)
.post(Entity.entity(customer, MediaType.APPLICATION_XML),
Response.class);
if (response.getStatus() == Status.CREATED.getStatusCode()) {
navigation = "customerCreated";
} else {
logger.log(Level.WARNING, "couldn''t create customer with " +
"id {0}. Status returned was {1}",
new Object[]{customer.getId(), response.getStatus()});
navigation = "customerError";
}
return navigation;
}
public String retrieveCustomer(String id) {
String navigation;
Customer customer =
client.target("http://localhost:8080/customer/webapi/Customer")
.path(id)
.request(MediaType.APPLICATION_XML)
.get(Customer.class);
if (customer == null) {
navigation = "customerError";
} else {
navigation = "customerRetrieved";
}
return navigation;
}
public List<Customer> retrieveAllCustomers() {
List<Customer> customers =
client.target("http://localhost:8080/customer/webapi/Customer")
.path("all")
.request(MediaType.APPLICATION_XML)
.get(new GenericType<List<Customer>>() {});
return customers;
}
}
This client uses the POST and GET methods.
All of these HTTP status codes indicate success: 201 for POST, 200 for
GET, and 204 for DELETE. For details about the meanings of HTTP
status codes, see
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
Running the customer Example
You can use either NetBeans IDE or Maven to build, package, deploy, and
run the customer application.
The following topics are addressed here:
To Build, Package, and Deploy the customer Example Using NetBeans IDE
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
tut-install/examples/jaxrs -
Select the
customerfolder. -
Click Open Project.
-
In the Projects tab, right-click the
customerproject and select Build.This command builds and packages the application into a WAR file,
customer.war, located in thetargetdirectory. Then, the WAR file is deployed to GlassFish Server. -
Open the web client in a browser at the following URL:
http://localhost:8080/customer/The web client allows you to create and view customers.
To Build, Package, and Deploy the customer Example Using Maven
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a terminal window, go to:
tut-install/examples/jaxrs/customer/ -
Enter the following command:
This command builds and packages the application into a WAR file,
customer.war, located in thetargetdirectory. Then, the WAR file is deployed to GlassFish Server. -
Open the web client in a browser at the following URL:
http://localhost:8080/customer/The web client allows you to create and view customers.