Java EE 7

Overview and catchup

@bentolor

Table of contents

Java EE history & timelines

  • Java EE 5 (May 11, 2006)
  • Java EE 6 (Dec 10, 2009)
  • Java EE 7 (May 28, 2013)
  • Java EE 8 (~ Q3/2016)

JEE 5 - Ease of Development

  • Annoations
  • JPA
  • EJB 3.0 (@Entity POJO beans)
  • XML Binding (JAXB)
  • XML Web Services (JAX-WS)

JEE 6 - Ease of Deployment

  • API Pruning: JAX-RPC -> JAX-WS, EJB -> JPA, JAXR, JSR88
  • Web Profile
  • EJBlite (No interfaces, JavaSE bootrapable)
  • Dependency Injection
  • Bean Validation
  • RESTful Services
  • Servlet Annotations

JEE 7 - Productivity, HTML5, Enterprise Demands

  • Web Sockets
  • JSON / REST
  • Servlet NIO
  • Simplified JMS
  • Batch Applications
  • More annotated POJO & less boilerplate
  • Concurrency Utilities
  • API Pruning: EJB CMP/BMP, JAX-RPC, Deployment API
  • Multi-tenancy (Cloud)

Application servers

JEE 7 implementations

as of 10/2014
  • GlassFish Server Open Source Edition 4.0 (Oracle, CDDL)
  • Wildfly 8.x (JBoss, LGPL)
  • TMAX JEUS 8 (TmaxSoft, Korea, proprietary)

Features at glance

Bean Validation

  • Support for methods (parameters, return values)
  • Default enable for: annotated, all, none
  • Veto support for packages / classes:
    @Vetoed
    public class NonProcessedBean {  }
    
    // package-info.java
    @Vetoed
    package com.nonprocessed.package;

Bean Validation - Method Constraints

@RequestScoped
public class MyBean {

    public String sayHello(@Size(max = 3) String name) {   }

    @Future       // return value constraint
    public Date showDate(boolean inFuture) {   }

    public String showList(@NotNull @Size(min = 1, max = 3) List list,
                           @NotNull String prefix) {
        // ...
    }

    public void saveZip(@ZipCode String zip) {  }
    public void saveZipIndia(@ZipCode(country = ZipCode.INDIA) String zip) {  }
}  

Bean Validation


// Each tests throws ConstraintViolationException with
// message constraint class and affected class member name

@Test
public void methodSizeTooLong() {
  bean.sayHello("Duke");
}

@Test
public void wrongReturnValue() {
  bean.showDate(false);
}

@Test
public void multipleParametersNullSecondParameter() {
  List<String> list = new ArrayList<>();
  list.add("bar");
  bean.showList(list, null);
}

JSON & RESTful Services

Create JSON

JsonObject jsonObject = Json.createObjectBuilder()
    .add("title", "The Matrix")
    .add("year", 1999)
    .add("cast", Json.createArrayBuilder()
            .add("Keanu Reaves")
            .add("Laurence Fishburne")
            .add("Carrie-Anne Moss"))
    .build();
try (JsonWriter writer = Json.createWriter(out)) {
  writer.write(jsonObject);
}

Read JSON

JsonReader jsonReader = Json.createReader(...);
JsonObject json = jsonReader.readObject();

assertTrue(json.containsKey("title"));
assertEquals("The Matrix", json.getString("title"));
assertEquals(1999, json.getInt("year"));
  

RESTful Services with JAX-RS

@ApplicationPath("webresources")
public class MyApplication extends Application { }
@Path("/fruit")
public class MyResource {

  @GET
  @Path("{name}")
  @Produces({"application/json", "application/xml"})
  public String get(@PathParam("name")String payload) {
      return Database.get(payload);
  }

  @POST
  public void post(String payload) {  Database.add(payload);  }

  @PUT
  public void put(String payload) {   Database.add(payload);  }

  @DELETE
  @Path("{name}")
  public void delete(@PathParam("name")String payload) {
      Database.delete(payload);
  }
}

JAX-RS with Bean Validation

@Path("/endpoint")
public class MyResource {

    @POST
    @Produces(MediaType.TEXT_PLAIN)
    public String post(@Size(min = 3) String payload) {
        return payload;
    }

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public void post2(@NotNull @FormParam("name")       String name,
                      @Min(1) @Max(10)@FormParam("age") int age) {
    }
}

Websocket Server

@ServerEndpoint(value="/websocket")
public class MyEndpoint {

    @OnMessage
    public void message(String message, Session client) {
        for (Session peer : client.getOpenSessions()) {
            peer.getBasicRemote().sendText(message);
        }
    }

    @OnMessage(maxMessageSize=6)
    public ByteBuffer echoBinary(ByteBuffer data) throws IOException {
        return data;
    }

    @OnClose
    public void onClose(CloseReason reason) {
        System.out.println("Closed: " + reason.getCloseCode()
                + ", " + reason.getReasonPhrase());
    }

    @OnError
    public void onError(Throwable t) {  t.printStackTrace();   }
}

Websocket Client

@ClientEndpoint
public class MyClient {
    @OnOpen
    public void onOpen(Session session) {
        try {
            session.getBasicRemote().sendText("Duke");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @OnMessage
    public void processMessage(String message) {
        System.out.println("Received message in client: " + message);
    }
}

Concurrency

  • Managing own threads in JEE is problematic
  • JEE7 introduces own, managed versions of java.util.concurrent utilities

Concurrency - Examples

Start managed threads
ManagedThreadFactory factory =
   (ManagedThreadFactory) ctx.lookup("java:comp/DefaultManagedThreadFactory");
Thread thread = factory.newThread(new MyTask(2)); // getting ManageableThread
thread.start();
Managed executor services
@Resource(name = "DefaultManagedScheduledExecutorService")
ManagedScheduledExecutorService executor;

ScheduledFuture<?> future = executor
  .scheduleAtFixedRate(new MyRunnableTask(5), 2, 3, TimeUnit.SECONDS);

Concurrency - In servlets

@WebServlet(urlPatterns = "/MyAsyncServlet", asyncSupported = true)
    public class MyAsyncServlet extends HttpServlet {

    @Resource(lookup="java:comp/DefaultManagedExecutorService")
    ManagedExecutorService executor;

    protected void processRequest(...) throws ... {
      AsyncContext ac = request.startAsync();
      ac.addListener(new AsyncListener() {
          public void onComplete(AsyncEvent event) throws IOException {}
          public void onTimeout(AsyncEvent event) throws IOException {}
          public void onError(AsyncEvent event) throws IOException {}
          public void onStartAsync(AsyncEvent event) throws IOException {}
      });

      executor.submit(new MyAsyncService(ac));
    }

Batch Processing

Batch processing is execution of "jobs" which are suitable for non-interactive, bulk-oriented and long-running tasks

Supports job/step/chunk listener, workflow definitions, concurrent steps, flow decisions

Defining batch jobs

<?xml version="1.0" encoding="UTF-8"?>
<job id="myJob" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
    <flow id="flow1" next="step3">
        <step id="step1" next="step2">
            <batchlet ref="myBatchlet1"/>
        </step>
        <step id="step2" >
            <chunk item-count="3">
                <reader ref="myItemReader"/>
                <writer ref="myItemWriter"/>
            </chunk>
        </step>
    </flow>
    <step id="step3" >
        <batchlet ref="myBatchlet2"/>
    </step>
</job>

Starting / Controlling jobs

JobOperator jobOperator = BatchRuntime.getJobOperator();
        Long executionId = jobOperator.start("myJob", new Properties());
        JobExecution jobExecution = jobOperator.getJobExecution(executionId);

        // ...

        List stepExecutions = jobOperator.getStepExecutions(executionId);
        for (StepExecution stepExecution : stepExecutions) {
            if (stepExecution.getStepName().equals("myStep")) {
              // ...
            }
        }

        assertEquals(jobExecution.getBatchStatus(), BatchStatus.COMPLETED);
    }

Dependency injection

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class SimpleGreetingBean {

    // built-in values
    @Inject HttpSession httpSession;
    @Inject ServletContext servletContext;
    @Inject Principal principal;

    // custom beans
    @Inject Greeting greeting;

    public String greet(String name) {
        System.out.println("session id: " + httpSession.getId());
        System.out.println("context path: " + servletContext.getContextPath());
        System.out.println("security principal: " + principal.getName());

        return "Hello " + name;
    }

}

Dependency injection (CDI)

  • Scopes:
    • @ApplicationScoped, @RequestScoped,
      @SessionScoped, @Singleton
  • @Interceptors intercepts any method invocations / lifecycle events on JEE managed classes
  • Similar @Decorator intercept business methods
  • Wiring events via @Observer annotation
  • @Alternative beans for DI with priority control.
    (Scope: beans archive)

CDI - @Decorators

public interface Greeting {
    public String greet(String name);
}

decorating calls..

@Decorator
public class MyDecorator implements Greeting {
    @Inject @Delegate @Any Greeting greeting;

    public String greet(String name) {
        return greeting.greet(name + " very much!");
    }
}

CDI - Event wiring

public interface EventReceiver {
	String getGreet();
}
@SessionScoped
public class GreetingReceiver implements EventReceiver, Serializable {
  private String greet = "Willkommen";

  void receive(@Observes String greet) {
  	this.greet = greet;
  }

  public String getGreet() {
  	return greet;
  }
}
public class GreetingSender implements EventSender {
  @Inject
  private Event event;

  public void send(String message) {
  	event.fire(message);
  }
}

EJB lite

EJB Lite is a subset of the features provided by EJB offering

  • Stateless, stateful, and singleton session beans
  • No EJB interfaces req'd
  • Interceptors
  • Container/bean-managed transactions
  • Declarative/programmatic security

EJB lite can be directly deployed within .jar archives.

Miscellanious

Multi-Tenancy

JPA 2.1 introduces Table discriminator

Default resources

Default resources for JSM, Concurrency, Context Service i.e. java:comp/DefaultJMSConnectionFactory

Servlet NIO

Support for non-blocking programming model for servlets, i.e. ReadListener.onDataAvailable() and WriteListener.onWritePossible()

Credits & Resources

Thank you :)