In passing
A simple API in the Concurrency Utilities allows competing actions of application components to be executed without compromising container integrity. Java SE's concurrency APIs can't be directly used in Java EE containers because the APIs are outside of the containers' resource management, and doing so will cause stability issues. Because of this the new Concurrency Utilities are now included as a Java EE-compliant extension of JSR 166. Existing functions are now managed by the container. java.util.concurrent.ExecutorService has been replaced by its enterprise counterpart, javax.enterprise.concurrent.ManagedExecutorService. A standard instance is now available via JNDI (Java Naming and Directory Interface), but it can also be injected directly:
@Resource(lookup="DefaultManagedExecutorService")
ManagedExecutorService executor;
The work to be executed is called a task and will implement the Runnable or the Callable interface.
public class MyTask implements Runnable {
@Override
public void run() {
//...
}
}
Then, the task is executed via the ManagedExecutorService:
Collection tasks = new ArrayList();
tasks.add(new MyTask());
executor.invokeAny(tasks);
In addition to the task, which doesn't have a return value, there is also the callable, which can have a return value. CDI beans can also be tasks. However, developers must be mindful of the scope. Only @Application and @Dependent Scope can be used as tasks. The javax.enterprise.concurrent.ManagedScheduledExecutorService enables developers to execute scheduled tasks. The service is called in the same way as the ExecutorService, the only difference being that the relevant times must be stated.
ScheduledFuture<?> f = executor.schedule(new MyTask(), 15,
TimeUnit.SECONDS);
The code will execute the task with a delay of 15 seconds. The container context can be used to provide functionality from application components such as class loaders, namespaces and security.
Welcome to the present of the web
Important among the modern web technologies that have been added to Java EE is the WebSockets approach. As a bi-directional communication protocol via TCP, this technology provides direct communication facilities between servers and clients, although WebSockets is an Internet Engineering Task Force (IETF) Request for Comments (RFC) that is incorporated into HTML5-compliant browsers by supporting JavaScript APIs. Unlike HTTP connections, TCP connections will be maintained persistently in the process. In its current state, JSR 356 does not implement all possibilities and focuses on the server-side provision of WebSocket endpoints, on receiving text, binary and control messages, on lifecycle events, and on the integration into Java EE Security. A simple endpoint for a chat looks like this:
@ServerEndpoint("/chat/{room}")
public class ChatServer {
@OnMessage
public void receiveMessage(String message, @PathParam("room") String room) {
//...
}
}
The method that is annotated via @OnMessage is used when a client message is received. Depending on the message format, the method parameter facilitates the processing of text messages via strings, binary messages via byte , and streams via InputStream. Primitive Java types or strings can be used in the server endpoint via @PathParam. @OnMessage is complemented by the lifecycle methods (@OnOpen, @OnClose and @OnError), which can be implemented. CDI is fully supported. As an alternative to the annotations approach, server endpoints can also be fully programmed via APIs, which means that they can be made available in Java SE. In an ideal scenario, the server communicates with a JavaScript client that is executed in the browser.
var websocket = new WebSocket("ws://localhost:8080/chatapp/chat");
However, Java classes can also be clients. The @ClientEndpoint annotation is available for this purpose:
@ClientEndpoint
public class ChatClient {
//...
}
As in the server scenario, it provides lifecycle events with the relevant annotated methods. Developers can use encoders and decoders to serialise application-specific data types in a similar way to JAX-RS. Unfortunately, they don't offer the option of simply registering providers; in this case, providers must be added to the server endpoint.
@ServerEndpoint(value = "/personservice",
encoders = {PersonEncoder.class},
decoders = {PersonDecoder.class})
The web.xml deployment descriptor's known security constraints also apply to WebSocket endpoints.
Years of stagnation overcome
After more than nine years of stagnation, the new version of the Java Message Services (JMS) can be considered the most comprehensive change. The adoption of Java SE] 7 approaches such as "try-with-resources", as well as the dependency injection concept, have streamlined and simplified the API. For example, the specification leads have combined the connection and session objects in the new JMSContext. Instead of having to work with two, the single new context is now sufficient and can even be injected. Consequently, there is no need to create or close it explicitly.
@Inject JMSContext context;
However, the API simplification efforts have been taken even further. For instance, new producer methods provide a smoother work flow. Sending a JMS message the new way is significantly less bulky:
TextMessage textMessage = context.createTextMessage(body);
context.createProducer().setPriority(1).setProperty("foo",
"bar").send(demoQueue, textMessage);
Producers are "lightweight" and can be created as needed. This completely eliminates the need to cache them. New message objects no longer need to be instantiated at all. With JMS 2.0, the required payload data can directly be submitted to the producer:
context.createProducer().send(demoQueue,"Hello The H");
Accordingly, type conversions to a specific class are no longer required when the data is received.
JMSConsumer consumer = context.createConsumer(demoQueue);
String result = "Receive " + consumer.receiveBody(String.class, 1000);
These changes have significantly simplified the work and avoid a lot of superfluous code. In this respect, the changes don't just affect the work within the Java EE specification, they also affect Java SE. In the Java EE container, the new additions require the use of a resource adapter, but this functionality should be provided by the server without any noticeable impact on developers.
Inspired by the Spring community
It has taken a long time for batch applications to become available in the Java Enterprise Edition. Modelled extensively after the concepts used in Spring Batch and sponsored by IBM, JSR 352 is now available for batch processing. The basic idea is to process a series of tasks that modify mass data in long intervals without any further interaction. A job is the main object. It is divided into individual "steps" that execute tasks according to known batch patterns (read, edit, write). Batch jobs are started via the batch operator:
JobOperator jo = BatchRuntime.getJobOperator();
Properties jobParams = new Properties();
jobParams.put("file.url", " testdata.txt");
long jobId = jo.start("extract-cities", jobParams);
In the example above, Properties are added to the batch job. These are transferred to the start method together with the name of the actual batch description. Under META-INF/batch-jobs/, the submitted name includes an identically named XML document that describes the job.
<job id="extractCity" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
<step id="populateCities" >
<chunk>
<reader ref="entryReader" />
<processor ref="entryProcessor"/>
<writer ref="entryWriter"/>
</chunk>
</step>
</job>
job, chunk and step describe the element-oriented processing type. "Batchlets" can be used to implement the task-oriented processing type. The three main classes are addressed from within the XML document by their bean name. Therefore, separate classes must be implemented for Reader, Processor and Writer:
@Named("entryReader")
public class EntryReader extends AbstractItemReader {
//...
@Override
public String readItem() {
//...
}
}
@Named("entryProcessor")
public class EntryProcessor implements ItemProcessor {
//...
@Override
public Object processItem(Object o) throws Exception {
//...
}
}
@Named("entryWriter")
public class EntryWriter extends AbstractItemWriter {
//...
@Override
public void writeItems(List<Object> list) throws Exception {
//...
}
}