New Features and Improvements
Java EE 8 is a big release, desired and anticipated by the global community for about four years. More than ever before, the whole platform is now even more robust, mature, and stable.
This chapter will cover the main APIs that we can highlight for Java EE 8. Not that they are the only topics covered by this release—far from it—but they have a big role in the enterprise context and are worthy of a careful look inside.
In this chapter, we will cover the following recipes:
- Running your first Bean Validation 2.0 code
- Running your first CDI 2.0 code
- Running your first JAX-RS 2.1 code
- Running your first JSF 2.3 code
- Running your first JSON-P 1.1 code
- Running your first JSON-B 1.0
- Running your first Servlet 4.0 code
- Running your first Security API 1.0
- Running your first MVC 1.0 code
Running your first Bean Validation 2.0 code
Bean Validation is a Java specification that basically helps you to protect your data. Through its API, you can validate fields and parameters, express constraints using annotations, and extend your customs' validation rules.
It can be used both with Java SE and Java EE.
In this recipe, you will have a glimpse of Bean Validation 2.0. It doesn't matter whether you are new to it or already using version 1.1; this content will help you get familiar with some of its new features.
Getting ready
First, you need to add the right Bean Validation dependency to your project, as follows:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.8.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b10</version>
</dependency>
</dependencies>
How to do it...
- First, we need to create an object with some fields to be validated:
public class User {
@NotBlank
private String name;
private String email;
@NotEmpty
private List<@PositiveOrZero Integer> profileId;
public User(String name, String email, List<Integer> profileId) {
this.name = name;
this.email = email;
this.profileId = profileId;
}
}
- Then we create a test class to validate those constraints:
public class UserTest {
private static Validator validator;
@BeforeClass
public static void setUpClass() {
validator = Validation.buildDefaultValidatorFactory()
.getValidator();
}
@Test
public void validUser() {
User user = new User(
"elder",
"elder@eldermoraes.com",
asList(1,2));
Set<ConstraintViolation<User>> cv = validator
.validate(user);
assertTrue(cv.isEmpty());
}
@Test
public void invalidName() {
User user = new User(
"",
"elder@eldermoraes.com",
asList(1,2));
Set<ConstraintViolation<User>> cv = validator
.validate(user);
assertEquals(1, cv.size());
}
@Test
public void invalidEmail() {
User user = new User(
"elder",
"elder-eldermoraes_com",
asList(1,2));
Set<ConstraintViolation<User>> cv = validator
.validate(user);
assertEquals(1, cv.size());
}
@Test
public void invalidId() {
User user = new User(
"elder",
"elder@eldermoraes.com",
asList(-1,-2,1,2));
Set<ConstraintViolation<User>> cv = validator
.validate(user);
assertEquals(2, cv.size());
}
}
How it works...
Our User class uses three of the new constraints introduced by Bean Validation 2.0:
- @NotBlank: Assures that the value is not null, empty, or an empty string (it trims the value before evaluation, to make sure there aren't spaces).
- @Email: Allows only a valid email format. Forget those crazy JavaScript functions!
- @NotEmpty: Ensures that a list has at least one item.
- @PositiveOrZero: Guarantees that a number is equal or greater than zero.
Then we create a test class (using JUnit) to test our validations. It first instantiates Validator:
@BeforeClass
public static void setUpClass() {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
Validator is an API that validates beans according to the constraints defined for them.
Our first test method tests a valid user, which is a User object that has:
- Name not empty
- Valid email
- profileId list only with integers greater than zero:
User user = new User(
"elder",
"elder@eldermoraes.com",
asList(1,2));
And finally, the validation:
Set<ConstraintViolation<User>> cv = validator.validate(user);
The validate() method from Validator returns a set of constraint violations found, if any, or an empty set if there are no violations at all.
So, for a valid user it should return an empty set:
assertTrue(cv.isEmpty());
And the other methods work with variations around this model:
- invalidName(): Uses an empty name
- invalidEmail(): Uses a malformed email
- invalidId(): Adds some negative numbers to the list
Note that the invalidId() method adds two negative numbers to the list:
asList(-1,-2,1,2));
So, we expect two constraint violations:
assertEquals(2, cv.size());
In other words, Validator checks not only the constraints violated, but how many times they are violated.
See also
- You can check the Bean Validation 2.0 specification at http://beanvalidation.org/2.0/spec/
- The full source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-beanvalidation/
Running your first CDI 2.0 code
Context and Dependency Injection (CDI) is certainly one of the most important APIs for the Java EE platform. In version 2.0, it also works with Java SE.
Nowadays, CDI has an impact on many other APIs in the Java EE platform. As said in an interview for Java EE 8 – The Next Frontier project:
– Ed Burns, JSF Spec Lead
There is a lot of new features in CDI 2.0. This recipe will cover Observer Ordering to give you a quick start.
Getting ready
First, you need to add the right CDI 2.0 dependency to your project. To make things easier at this point, we are going to use CDI SE, the dependency that allows you to use CDI without a Java EE server:
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-shaded</artifactId>
<version>3.0.0.Final</version>
</dependency>
How to do it...
This recipe will show you one of the main features introduced by CDI 2.0: Ordered Observers. Now, you can turn the observers job into something predictable:
- First, let's make an event to be observed:
public class MyEvent {
private final String value;
public MyEvent(String value){
this.value = value;
}
public String getValue(){
return value;
}
}
- Now, we build our observers and the server that will fire them:
public class OrderedObserver {
public static void main(String[] args){
try(SeContainer container =
SeContainerInitializer.newInstance().initialize()){
container
.getBeanManager()
.fireEvent(new MyEvent("event: " +
System.currentTimeMillis()));
}
}
public void thisEventBefore(
@Observes @Priority(Interceptor.Priority
.APPLICATION - 200)
MyEvent event){
System.out.println("thisEventBefore: " + event.getValue());
}
public void thisEventAfter(
@Observes @Priority(Interceptor.Priority
.APPLICATION + 200)
MyEvent event){
System.out.println("thisEventAfter: " + event.getValue());
}
}
Also, don't forget to add the beans.xml file into the META-INF folder:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
- Once you run it, you should see a result like this:
INFO: WELD-ENV-002003: Weld SE container
353db40d-e670-431d-b7be-4275b1813782 initialized
thisEventBefore: event -> 1501818268764
thisEventAfter: event -> 1501818268764
How it works...
First, we are building a server to manage our event and observers:
public static void main(String[] args){
try(SeContainer container =
SeContainerInitializer.newInstance().initialize()){
container
.getBeanManager()
.fireEvent(new ExampleEvent("event: "
+ System.currentTimeMillis()));
}
}
This will give us all the resources needed to run the recipe as if it was a Java EE server.
Then we build an observer:
public void thisEventBefore(
@Observes @Priority(Interceptor.Priority.APPLICATION - 200)
MyEvent event){
System.out.println("thisEventBefore: " + event.getValue());
}
So, we have three important topics:
- @Observes: This annotation is used to tell the server that it needs to watch the events fired with MyEvent
- @Priority: This annotation informs in which priority order this observer needs to run; it receives an int parameter, and the execution order is ascendant
- MyEvent event: The event being observed
On the thisEventBefore method and thisEventAfter, we only changed the @Priority value and the server took care of running it in the right order.
There's more...
The behavior would be exactly the same in a Java EE 8 server. You just wouldn't need SeContainerInitializer and would need to change the dependencies to the following:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
See also
- You can stay tuned with everything related to the CDI Specification at http://www.cdi-spec.org/
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-cdi
Running your first JAX-RS 2.1 code
JAX-RS is an API designed to give a portable and standard way for building RESTful web services in Java. This is one of the most used technologies for data transporting between different applications that uses some network (internet included) for communication.
One of the coolest features introduced by the 2.1 release is Server-Sent Events (SSE), which will be covered in this recipe. SSE is a specification created by HTML5 where it has established a channel between server and client, one way only from server to client. It is a protocol that transports a message containing some data.
Getting ready
Let's start by adding the right dependency to our project:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.26-b09</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.26-b09</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.26-b09</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
You surely noticed that we are using Jersey here. Why? Because Jersey is the reference implementation for JAX-RS, which means that all JAX-RS specifications are first implemented through Jersey.
Moreover, with Jersey we can use Grizzly to start a small local server, which will be useful for this recipe, as we need just a few server features to show the SSE behavior.
Further on in this book, we will use a full GlassFish to build more JAX-RS recipes.
How to do it...
- First, we create a class that will be our server:
public class ServerMock {
public static final URI CONTEXT =
URI.create("http://localhost:8080/");
public static final String BASE_PATH = "ssevents";
public static void main(String[] args) {
try {
final ResourceConfig resourceConfig = new
ResourceConfig(SseResource.class);
final HttpServer server =
GrizzlyHttpServerFactory.createHttpServer(CONTEXT,
resourceConfig, false);
server.start();
System.out.println(String.format("Mock Server started
at %s%s", CONTEXT, BASE_PATH));
Thread.currentThread().join();
} catch (IOException | InterruptedException ex) {
System.out.println(ex.getMessage());
}
}
}
- Then, we create a JAX-RS endpoint to send the events to the clients:
@Path(ServerMock.BASE_PATH)
public class SseResource {
private static volatile SseEventSink SINK = null;
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public void getMessageQueue(@Context SseEventSink sink) {
SseResource.SINK = sink;
}
@POST
public void addMessage(final String message, @Context Sse sse)
throws IOException {
if (SINK != null) {
SINK.send(sse.newEventBuilder()
.name("sse-message")
.id(String.valueOf(System.currentTimeMillis()))
.data(String.class, message)
.comment("")
.build());
}
}
}
- Then, we create a client class to consume the events generated from the server:
public class ClientConsumer {
public static final Client CLIENT = ClientBuilder.newClient();
public static final WebTarget WEB_TARGET =
CLIENT.target(ServerMock.CONTEXT
+ BASE_PATH);
public static void main(String[] args) {
consume();
}
private static void consume() {
try (final SseEventSource sseSource =
SseEventSource
.target(WEB_TARGET)
.build()) {
sseSource.register(System.out::println);
sseSource.open();
for (int counter=0; counter < 5; counter++) {
System.out.println(" ");
for (int innerCounter=0; innerCounter < 5;
innerCounter++) {
WEB_TARGET.request().post(Entity.json("event "
+ innerCounter));
}
Thread.sleep(1000);
}
CLIENT.close();
System.out.println("\n All messages consumed");
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
To try it out, you have to first run the ServerMock class and then the ClientConsumer class. If everything worked well, you should see something like this:
InboundEvent{name='sse-message', id='1502228257736', comment='', data=event 0}
InboundEvent{name='sse-message', id='1502228257753', comment='', data=event 1}
InboundEvent{name='sse-message', id='1502228257758', comment='', data=event 2}
InboundEvent{name='sse-message', id='1502228257763', comment='', data=event 3}
InboundEvent{name='sse-message', id='1502228257768', comment='', data=event 4}
These are the messages sent from the server to the client.
How it works...
This recipe is made up of three parts:
- The server, represented by the ServerMock class
- The SSE engine, represented by the SseResource class
- The client, represented by the ClientConsumer class
So once ServerMock is instantiated, it registers the SseResource class:
final ResourceConfig resourceConfig = new ResourceConfig(SseResource.class);
final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(CONTEXT, resourceConfig, false);
server.start();
Then two key methods from SseResource take place. The first one adds messages to the server queue:
addMessage(final String message, @Context Sse sse)
The second one consumes this queue and sends the messages to the clients:
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public void getMessageQueue(@Context SseEventSink sink)
Note that this one has a media type SERVER_SENT_EVENTS, introduced in this version for this very purpose. And finally, we have our client. In this recipe, it is both posting and consuming messages.
It consumes here:
sseSource.register(System.out::println);
sseSource.open();
It posts here:
ServerMock.WEB_TARGET.request().post(Entity.json("event " + innerCounter));
See also
- You can stay tuned with everything related to JAX-RS at https://github.com/jax-rs
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-jaxrs
Running your first JSF 2.3 code
JavaServer Faces (JSF) is the Java technology made to simplify the process of building a UIs, despite how it's made for the frontend and the UI is built in the backend.
With JSF, you can build components and use (or reuse) them in the UI in an extensible way. You can also use other powerful APIs, such as CDI and Bean Validation, to improve your application and its architecture.
In this recipe, we will use the Validator and Converter interfaces with the new feature introduced by version 2.3, which is the possibility of using them with generic parameters.
Getting ready
First, we need to add the dependencies needed:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
How to do it...
- Let's create a User class as the main object of our recipe:
public class User implements Serializable {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
//DON'T FORGET THE GETTERS AND SETTERS
//THIS RECIPE WON'T WORK WITHOUT THEM
}
- Now, we create a UserBean class to manage our UI:
@Named
@ViewScoped
public class UserBean implements Serializable {
private User user;
public UserBean(){
user = new User("Elder Moraes", "elder@eldermoraes.com");
}
public void userAction(){
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Name|Password welformed"));
}
//DON'T FORGET THE GETTERS AND SETTERS
//THIS RECIPE WON'T WORK WITHOUT THEM
}
- Now, we implement the Converter interface with a User parameter:
@FacesConverter("userConverter")
public class UserConverter implements Converter<User> {
@Override
public String getAsString(FacesContext fc, UIComponent uic,
User user) {
return user.getName() + "|" + user.getEmail();
}
@Override
public User getAsObject(FacesContext fc, UIComponent uic,
String string) {
return new User(string.substring(0, string.indexOf("|")),
string.substring(string.indexOf("|") + 1));
}
}
- Now, we implement the Validator interface with a User parameter:
@FacesValidator("userValidator")
public class UserValidator implements Validator<User> {
@Override
public void validate(FacesContext fc, UIComponent uic,
User user)
throws ValidatorException {
if(!user.getEmail().contains("@")){
throw new ValidatorException(new FacesMessage(null,
"Malformed e-mail"));
}
}
}
- And then we create our UI using all of them:
<h:body>
<h:form>
<h:panelGrid columns="3">
<h:outputLabel value="Name|E-mail:"
for="userNameEmail"/>
<h:inputText id="userNameEmail"
value="#{userBean.user}"
converter="userConverter" validator="userValidator"/>
<h:message for="userNameEmail"/>
</h:panelGrid>
<h:commandButton value="Validate"
action="#{userBean.userAction()}"/>
</h:form>
</h:body>
Don't forget to run it in a Java EE 8 server.
How it works...
The UserBean class manages the communication between the UI and the server. Once you instantiate the user object, it is available for both of them.
That's why when you run it, the Name | E-mail is already filled (the user object is instantiated when the UserBean class is created by the server).
We associated the userAction() method from the UserBean class to the Validate button of the UI:
<h:commandButton value="Validate" action="#{userBean.userAction()}"/>
You can create other methods in UserBean and do the same to empower your application.
The whole core of our recipe is represented by just a single line in the UI:
<h:inputText id="userNameEmail" value="#{userBean.user}" converter="userConverter" validator="userValidator"/>
So, our two implemented interfaces used here are userConverter and userValidator.
Basically, the UserConverter class (with getAsString and getAsObject methods) converts an object to/from a string and vice versa, according to the logic defined by you.
We have just mentioned it in the preceding code snippet:
value="#{userBean.user}"
The server uses the userConverter object, calls the getAsString method, and prints the result using the preceding expression language.
Finally, the UserValidator class is automatically called when you submit the form, by calling its validate method, and applying the rules defined by you.
There's more...
You could increase the validators by adding a Bean Validation on it and, for example, defining the email property from User with an @Email constraint.
See also
- You can stay tuned with everything related to JSF at https://javaserverfaces.github.io/
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-jsf
Running your first JSON-P 1.1 code
JSON-Pointer is the Java API for JSON processing. By processing, we mean generating, transforming, parsing, and querying JSON strings and/or objects.
In this recipe, you will learn how to use JSON Pointer to get a specific value from a JSON message in a very easy way.
Getting ready
Let's get our dependency:
<dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
</dependency>
How to do it...
- First, we define a JSON message to represent a User object:
{
"user": {
"email": "elder@eldermoraes.com",
"name": "Elder",
"profile": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
}
]
}
}
- Now, we create a method to read it and print the values we want:
public class JPointer {
public static void main(String[] args) throws IOException{
try (InputStream is =
JPointer.class.getClassLoader().getResourceAsStream("user.json");
JsonReader jr = Json.createReader(is)) {
JsonStructure js = jr.read();
JsonPointer jp = Json.createPointer("/user/profile");
JsonValue jv = jp.getValue(js);
System.out.println("profile: " + jv);
}
}
}
The execution of this code prints the following:
profile: [{"id":1},{"id":2},{"id":3}]
How it works...
The JSON Pointer is a standard defined by the Internet Engineering Task Force (IETF) under Request for Comments (RFC) 6901. The standard basically says that a JSON Pointer is a string that identifies a specific value in a JSON document.
Without a JSON Pointer, you would need to parse the whole message and iterate through it until you find the desired value; probably lots of ifs, elses, and things like that.
So, JSON Pointer helps you to decrease the written code dramatically by doing this kind of operation in a very elegant way.
See also
- You can stay tuned with everything related to JSON-P at https://javaee.github.io/jsonp/
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-jsonp
Running your first JSON-B code
JSON-B is an API for converting Java objects to/from JSON messages in a standardized way. It defines a default mapping algorithm to convert Java classes to JSON and still lets you customize your own algorithms.
With JSON-B, Java EE now has a complete set of tools to work with JSON, such as JSON API, and JSON-P. No third-party frameworks are needed anymore (although you are still free to use them).
This quick recipe will show you how to use JSON-B to convert a Java object to and from a JSON message.
Getting ready
Let's add our dependencies to the project:
<dependencies>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
How to do it...
- Let's create a User class as a model for our JSON message:
public class User {
private String name;
private String email;
public User(){
}
public User(String name, String email) {
this.name = name;
this.email = email;
}
@Override
public String toString() {
return "User{" + "name=" + name + ", email=" + email + '}';
}
//DON'T FORGET THE GETTERS AND SETTERS
//THIS RECIPE WON'T WORK WITHOUT THEM
}
- Then, let's create a class to use JSON-B to transform an object:
public class JsonBUser {
public static void main(String[] args) throws Exception {
User user = new User("Elder", "elder@eldermoraes.com");
Jsonb jb = JsonbBuilder.create();
String jsonUser = jb.toJson(user);
User u = jb.fromJson(jsonUser, User.class);
jb.close();
System.out.println("json: " + jsonUser);
System.out.println("user: " + u);
}
}
The result printed is:
json: {"email":"elder@eldermoraes.com","name":"Elder"}
user: User{name=Elder, email=elder@eldermoraes.com}
The first line is the object transformed into a JSON string. The second is the same string converted into an object.
How it works...
It uses the getters and setters defined in the User class to transform both ways and that's why they are so important.
See also
- You can stay tuned with everything related to JSON-B at http://json-b.net/
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-jsonb
Running your first Servlet 4.0 code
Servlet 4.0 is one the of biggest APIs of Java EE 8. Since the very beginning of the Java EE platform (the old J2EE), the Servlet specification has always played a key role.
The coolest additions of this version are surely HTTP/2.0 and Server Push. Both of them bring performance improvements to your application.
This recipe will use Server Push to do one of the most basic tasks in a web page—loading an image.
Getting ready
Let's add the dependencies that we need:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
How to do it...
- We will create a servlet:
@WebServlet(name = "ServerPush", urlPatterns = {"/ServerPush"})
public class ServerPush extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse
response) throws ServletException, IOException {
PushBuilder pb = request.newPushBuilder();
if (pb != null) {
pb.path("images/javaee-logo.png")
.addHeader("content-type", "image/png")
.push();
}
try (PrintWriter writer = response.getWriter();) {
StringBuilder html = new StringBuilder();
html.append("<html>");
html.append("<center>");
html.append("<img src='images/javaee-logo.png'><br>");
html.append("<h2>Image pushed by ServerPush</h2>");
html.append("</center>");
html.append("</html>");
writer.write(html.toString());
}
}
}
- To try it, run the project in a Java EE 8 server and open this URL:
https://localhost:8080/ch01-servlet/ServerPush
How it works...
We use the PushBuilder object to send an image to the client before it is requested by the img src tag. In other words, the browser doesn't need to do another request (what it usually does with img src) to have an image available for rendering.
It might seem as if it doesn't make too much difference for a single image, but it would with dozens, hundreds, or thousands of images. Less traffic for your client and from your server. Better performance for all!
There's more...
If you are using JSF, you can get the benefits from Server Push for free! You don't even need to rewrite a single line of your code, as JSF relies on the Server Push specification.
Just make sure that you run it under the HTTPS protocol, as HTTP/2.0 only works under it.
See also
- You can stay tuned with everything related to the Servlet specification at https://github.com/javaee/servlet-spec
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-servlet
Running your first Security API code
Security is one of the top concerns when you build an enterprise application. Luckily, the Java EE platform now has this API that handles many of the enterprise requirements in a standardized way.
In this recipe, you will learn how to define roles and give them the right authorization based on rules defined in the methods that manage sensitive data.
Getting ready
We start by adding our dependencies to the project:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>openejb-core</artifactId>
<version>7.0.4</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
How to do it...
- We first create a User entity:
@Entity
public class User implements Serializable{
@Id
private Long id;
private String name;
private String email;
public User(){
}
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
//DON'T FORGET THE GETTERS AND SETTERS
//THIS RECIPE WON'T WORK WITHOUT THEM
}
- Here, we create a class to store our security roles:
public class Roles {
public static final String ADMIN = "ADMIN";
public static final String OPERATOR = "OPERATOR";
}
- Then, we create a stateful bean to manage our user operations:
@Stateful
public class UserBean {
@PersistenceContext(unitName = "ch01-security-pu",
type = PersistenceContextType.EXTENDED)
private EntityManager em;
@RolesAllowed({Roles.ADMIN, Roles.OPERATOR})
public void add(User user){
em.persist(user);
}
@RolesAllowed({Roles.ADMIN})
public void remove(User user){
em.remove(user);
}
@RolesAllowed({Roles.ADMIN})
public void update(User user){
em.merge(user);
}
@PermitAll
public List<User> get(){
Query q = em.createQuery("SELECT u FROM User as u ");
return q.getResultList();
}
- Now, we need to create an executor for each role:
public class RoleExecutor {
public interface Executable {
void execute() throws Exception;
}
@Stateless
@RunAs(Roles.ADMIN)
public static class AdminExecutor {
public void run(Executable executable) throws Exception {
executable.execute();
}
}
@Stateless
@RunAs(Roles.OPERATOR)
public static class OperatorExecutor {
public void run(Executable executable) throws Exception {
executable.execute();
}
}
}
- And finally, we create a test class to try our security rules.
Our code uses three test methods: asAdmin(), asOperator(), and asAnonymous().
- First, it tests asAdmin():
//Lot of setup code before this point
@Test
public void asAdmin() throws Exception {
adminExecutor.run(() -> {
userBean.add(new User(1L, "user1", "user1@user.com"));
userBean.add(new User(2L, "user2", "user2@user.com"));
userBean.add(new User(3L, "user3", "user3@user.com"));
userBean.add(new User(4L, "user4", "user4@user.com"));
List<User> list = userBean.get();
list.forEach((user) -> {
userBean.remove(user);
});
Assert.assertEquals("userBean.get()", 0,
userBean.get().size());
});
}
- Then it tests asOperator():
@Test
public void asOperator() throws Exception {
operatorExecutor.run(() -> {
userBean.add(new User(1L, "user1", "user1@user.com"));
userBean.add(new User(2L, "user2", "user2@user.com"));
userBean.add(new User(3L, "user3", "user3@user.com"));
userBean.add(new User(4L, "user4", "user4@user.com"));
List<User> list = userBean.get();
list.forEach((user) -> {
try {
userBean.remove(user);
Assert.fail("Operator was able to remove user " +
user.getName());
} catch (EJBAccessException e) {
}
});
Assert.assertEquals("userBean.get()", 4,
userBean.get().size());
});
}
- And, finally it tests asAnonymous():
@Test
public void asAnonymous() {
try {
userBean.add(new User(1L, "elder",
"elder@eldermoraes.com"));
Assert.fail("Anonymous user should not add users");
} catch (EJBAccessException e) {
}
try {
userBean.remove(new User(1L, "elder",
"elder@eldermoraes.com"));
Assert.fail("Anonymous user should not remove users");
} catch (EJBAccessException e) {
}
try {
userBean.get();
} catch (EJBAccessException e) {
Assert.fail("Everyone can list users");
}
}
How it works...
The whole point in this recipe is to do with the @RolesAllowed, @RunsAs, and @PermitAll annotations. They define what operations each role can do and what happens when a user tries an operation using the wrong role.
There's more...
What we did here is called programmatic security; that is, we defined the security rules and roles through our code (the program). There's another approach called declarative security, where you declare the rules and roles through application and server configurations.
One good step up for this recipe is if you evolve the roles management to a source outside the application, such as a database or a service.
See also
- You can stay tuned with everything related to Security API at https://github.com/javaee-security-spec
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-security
Running your first MVC 1.0 code
If you are following the news about Java EE 8, you may now be wondering: why is MVC 1.0 here if it was dropped from the Java EE 8 umbrella?
Yes, it is true. MVC 1.0 doesn't belong (anymore) to the Java EE 8 release. But it didn't reduce the importance of this great API and I'm sure it will change the way some other APIs work in future releases (for example, JSF).
So why not cover it here? You will use it anyway.
This recipe will show you how to use a Controller (the C) to inject a Model (the M) into the View (the V). It also brings some CDI and JAX-RS to the party.
Getting ready
Add the proper dependencies to your project:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.mvc</groupId>
<artifactId>javax.mvc-api</artifactId>
<version>1.0-pr</version>
</dependency>
How to do it...
- Start by creating a root for your JAX-RS endpoints:
@ApplicationPath("webresources")
public class AppConfig extends Application{
}
- Create a User class (this will be your MODEL):
public class User {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
//DON'T FORGET THE GETTERS AND SETTERS
//THIS RECIPE WON'T WORK WITHOUT THEM
}
- Now, create a Session Bean, which will be injected later in your Controller:
@Stateless
public class UserBean {
public User getUser(){
return new User("Elder", "elder@eldermoraes.com");
}
}
- Then, create the Controller:
@Controller
@Path("userController")
public class UserController {
@Inject
Models models;
@Inject
UserBean userBean;
@GET
public String user(){
models.put("user", userBean.getUser());
return "/user.jsp";
}
}
- And finally, the web page (the View):
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
<title>User MVC</title>
</head>
<body>
<h1>${user.name}/${user.email}</h1>
</body>
Run it on a Java EE 8 server and access this URL:
http://localhost:8080/ch01-mvc/webresources/userController
How it works...
The main actor in this whole scenario is the Models class injected into the Controller:
@Inject
Models models;
It's a class from MVC 1.0 API that owns the responsibility, in this recipe, of letting the User object be available for the View layer. It's injected (using CDI) and uses another injected bean, userBean, to do it:
models.put("user", userBean.getUser());
So, the View can easily access the values from the User object using expression language:
<h1>${user.name}/${user.email}</h1>
See also
- You can stay tuned with everything related to MVC specification at https://github.com/mvc-spec
- The source code of this recipe is at https://github.com/eldermoraes/javaee8-cookbook/tree/master/chapter01/ch01-mvc