The customer Example Application (original) (raw)
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. SeeChapter 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 Customer and Address Entity Classes
- The CustomerService Class
- Using the JAX-RS Client in the CustomerBean Classes
- Running the customer Example
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
Customer
andAddress
entity classes. These classes model the data of the application and contain JAXB annotations. - The
CustomerService
resource class. This class contains JAX-RS resource methods that perform operations onCustomer
instances represented as XML or JSON data using JAXB. See The CustomerService Class for details. - The
CustomerBean
session bean that acts as a backing bean for the web client.CustomerBean
uses 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 theaddress
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 forGET
, and 204 for DELETE
. For details about the meanings of HTTP status codes, seehttp://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
- To Build, Package, and Deploy the customer Example Using Maven
To Build, Package, and Deploy the customer Example Using NetBeans IDE
- Make sure that GlassFish Server has been started (seeStarting 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
customer
folder. - Click Open Project.
- In the Projects tab, right-click the
customer
project and select Build.
This command builds and packages the application into a WAR file,customer.war
, located in thetarget
directory. 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 (seeStarting 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 thetarget
directory. 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.