November 17, 2017

Java EE 7 Performance Monitor with Interceptors, Event and Observes

Lets say you want to performance monitor your business class, that can be achieved with Java EE 7 Interceptors and @Observes. Lets start with the interceptor. Here will only want to encapsulate the actual aggregation and after collecting we use the Java EE 7 Event to send it to the @Observes. A clean separation of concerns.

package se.magnuskkarlsson.example.javaee7;

import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public class PerformanceInterceptor {

    @Inject
    Event<PerformanceEvent> events;
    
    @AroundInvoke
    public Object intercept(InvocationContext ctx) throws Exception {
        String className = ctx.getTarget().getClass().getName();
        String methodName = ctx.getMethod().getName();
        long start = System.currentTimeMillis();
        Object object = null;
        try {
            object = ctx.proceed();
        } finally {
            long duration = System.currentTimeMillis() - start;
            events.fire(new PerformanceEvent(className, methodName, duration));
        }
        return object;
    }
}

And the class that holds the data is a POJO.

package se.magnuskkarlsson.example.javaee7;

public class PerformanceEvent {
   
    private final String clazz;
    private final String method;
    private final long duration;

    public PerformanceEvent(String clazz, String method, long duration) {
        this.clazz = clazz;
        this.method = method;
        this.duration = duration;
    }

    public String getClazz() {
        return clazz;
    }

    public String getMethod() {
        return method;
    }

    public long getDuration() {
        return duration;
    }

    @Override
    public String toString() {
        return "PerformanceEvent{" + "clazz=" + clazz + ", method=" + method + ", duration=" + duration + '}';
    }
    
}

And the @Observes.

package se.magnuskkarlsson.example.javaee7;

import java.util.logging.Logger;
import javax.enterprise.event.Observes;

public class PerformanceObserver {

    private final Logger log = Logger.getLogger(PerformanceObserver.class.getName());
    
    public void log(@Observes PerformanceEvent event) {
        log.info(event.toString());
    }

}

And to use in your class that we want to performance measure.

package se.magnuskkarlsson.example.javaee7.control;

import se.magnuskkarlsson.example.javaee7.PerformanceInterceptor;

@Stateless
@Interceptors(PerformanceInterceptor.class)
public class EmployeeBean {

// the public methods we want to measure goes here ...
}

And when we run it

00:37:38,008 INFO  [se.magnuskkarlsson.example.javaee7.PerformanceObserver] (default task-9) PerformanceEvent{clazz=se.magnuskkarlsson.example.javaee7.control.EmployeeBean, method=delete, duration=2}

Java EE 7 Cross Cutting Interceptor Example

Lets say you need a logging feature for all you business class. Instead of writing repeatable code in yours businesses classes, lets use a Java EE 7 interceptor instead.

package se.magnuskkarlsson.example.javaee7;

import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public class TraceLogger {

    private final Logger log = Logger.getLogger(AuditLogger.class.getName());

    @AroundInvoke
    public Object intercept(InvocationContext ctx) throws Exception {
        String className = ctx.getTarget().getClass().getName();
        String methodName = ctx.getMethod().getName();
        List<Object> paramaters = Arrays.asList(ctx.getParameters());
        log.info(className + "#" + methodName + " Starting " + paramaters + " ...");
        Object object = null;
        try {
            object = ctx.proceed();
        } finally {
            log.info(className + "#" + methodName + " Finished.");
        }
        return object;
    }

}

And to use it.

package se.magnuskkarlsson.example.javaee7.control;

import javax.interceptor.Interceptors;
import se.magnuskkarlsson.example.javaee7.AuditLogger;

@Stateless
@Interceptors(TraceLogger.class)
public class EmployeeBean {
...
// public business method goes here...
}

And to make CDI work you need WEB-INF/beans.xml. Note that in Java EE 7 you need to declare your interceptors in beans.xml, that you used to in Java EE 6.

<?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>

Making Reusable JUnit Setup with TestRule and @Rule

In the below JAX-RS test we can extract the setup code to a reusable JUnit TestRule class.

public class EmployeeRestIT {
    private Client client;
    private WebTarget target;
    
    @Before
    public void setUp() throws Exception {
        client = ClientBuilder.newClient();
        target = client.target("http://localhost:8080/example-javaee7/rest/employee");
    }
...
}

And the JUnit TestRule class.

package se.magnuskkarlsson.example.javaee7;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class JaxRSClientTestRule implements TestRule {

    private final Client client;
    private final WebTarget target;

    private JaxRSClientTestRule(String uri) {
        client = ClientBuilder.newClient();
        target = client.target(uri);
    }

    public final static JaxRSClientTestRule buildWithUri(String uri) {
        return new JaxRSClientTestRule(uri);
    }
    
    public Client client() {
        return client;
    }
    
    public WebTarget target() {
        return target;
    }
    
    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {

            @Override
            public void evaluate() throws Throwable {
                base.evaluate();
                client.close();
            }
        };
    }

}

And to use the JUnit TestRule class in our JUnit test class.

package se.magnuskkarlsson.example.javaee7.boundary;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.client.Entity;
import static javax.ws.rs.core.MediaType.*;
import javax.ws.rs.core.Response;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import se.magnuskkarlsson.example.javaee7.JaxRSClientTestRule;
import static se.magnuskkarlsson.example.javaee7.JaxRSClientTestRule.buildWithUri;

public class EmployeeRestIT {
    
    @Rule
    public JaxRSClientTestRule rule = buildWithUri("http://localhost:8080/example-javaee7/rest/employee");

    @Test
    public void crud() throws Exception {
        JsonObjectBuilder builderCreate = Json.createObjectBuilder();
        JsonObject input = builderCreate.add("name", "Foo Bar").build();
        Response respCreate = rule.target().request(APPLICATION_JSON).post(Entity.json(input));
        assertThat(respCreate.getStatus(), is(201));
        String location = respCreate.getHeaderString("Location");
        assertNotNull(location);

        Response respGet = rule.client().target(location).request(APPLICATION_JSON).get();
        assertThat(respGet.getStatus(), is(200));
        JsonObject payload = respGet.readEntity(JsonObject.class);
        System.out.println("payload='" + payload + "'");
        
        int id = payload.getInt("id");
        JsonObjectBuilder builderUpdate = Json.createObjectBuilder();
        JsonObject update = builderUpdate.add("id", id).add("name", "UPDATED!").build();
        Response respUpdate = rule.target().request(APPLICATION_JSON).put(Entity.json(update));
        assertThat(respCreate.getStatus(), is(201));
        System.out.println("respUpdate=" + respUpdate.readEntity(JsonObject.class));
        
        Response respDelete = rule.target().path("/" + id).request(APPLICATION_JSON).delete();
        assertThat(respDelete.getStatus(), is(204));
    }
}

November 16, 2017

Java EE 7 Designing JAX-RS with System Test

Whenever building a Java EE 6 or 7 application always use the javax:javaee-api maven dependency and only that. So lets start with a Java EE 7 maven pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>se.magnuskkarlsson.examples</groupId>
    <artifactId>example-javaee7</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>example-javaee7</finalName>
    </build>
</project>

To make JAX-RS work we need to add an class that extends Application and annotated with @ApplicationPath.

package se.magnuskkarlsson.example.javaee7;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/rest")
public class JavaEE7Application extends Application {
}

Then we can write our Boundary JAX-RS class.

package se.magnuskkarlsson.example.javaee7.boundary;

import java.net.URI;
import java.util.List;
import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import se.magnuskkarlsson.example.javaee7.control.EmployeeBean;

import se.magnuskkarlsson.example.javaee7.entity.Employee;

@Path("/employee")
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class EmployeeRest {

    @Inject
    EmployeeBean bean;

    // returns 200 OK if found, othereise 204 No Content
    @GET
    @Path("/{id}")
    public Employee findById(@PathParam(value = "id") long id) {
        return bean.findById(id);
    }

    // returns 200 OK, otherwise empty JsonArray
    @GET
    public List<Employee> findAll() {
        return bean.findAll();
    }

    // returns 201 Created and Location header, otherwise 400 Bad Request and reason in body
    @POST
    public Response create(@Context UriInfo uriInfo, @Valid Employee employee) {
        long id = bean.create(employee).getId();
        URI location = uriInfo.getAbsolutePathBuilder().path("/" + id).build();
        return Response.created(location).build();
    }

    // returns 200 OK, otherwise 400 Bad Request and reason in body
    @PUT
    public Employee update(@Valid Employee employee) {
        return bean.update(employee);
    }

    // returns always 204 No Content
    @DELETE
    @Path("/{id}")
    public void delete(@PathParam(value = "id") long id) {
        bean.delete(id);
    }

}

And our business logic we encapsulate in a Controller class.

package se.magnuskkarlsson.example.javaee7.control;

import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import se.magnuskkarlsson.example.javaee7.entity.Employee;

@Stateless
public class EmployeeBean {

    @PersistenceContext
    private EntityManager em;

    public Employee findById(long id) {
        return em.find(Employee.class, id);
    }

    public List<Employee> findAll() {
        return em.createQuery("FROM Employee e").getResultList();
    }

    public Employee create(Employee employee) {
        em.persist(employee);
        return employee;
    }

    public Employee update(Employee employee) {
        em.merge(employee);
        return employee;
    }

    public void delete(long id) {
        try {
            Employee employee = em.getReference(Employee.class, id);
            em.remove(employee);
        } catch (EntityNotFoundException IGNORE) {
            // we want to delete anyway ...
        }
    }

}

And finally our Entity class.

package se.magnuskkarlsson.example.javaee7.entity;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Size;

import javax.xml.bind.annotation.XmlRootElement;

@Entity
@XmlRootElement
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    private Long id;
    @Column(length = 255)
    @Size(min = 3, max = 255)
    private String name;

    public Employee() {
    }

    public Employee(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

We also need to a META-INF/persistence.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="javaee7" transaction-type="JTA">
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
        </properties>
    </persistence-unit>
</persistence>

And a WEB-INF/beans.xml file to make our application CDI aware.

<?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>

To test this build and deploy your application to, e.g. JBoss EAP 7.

Then create a new simple java project that we suffix with -st, for system test. In that pom.xml we need to add a jax-rs and json-p implementation dependency.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>se.magnuskkarlsson.examples</groupId>
    <artifactId>example-javaee7-st</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- jax-rs reference implementation -->
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>2.17</version>
            <scope>test</scope>
        </dependency>
        <!-- json-p reference implementation -->
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.json</artifactId>
            <version>1.0.4</version>
            <scope>test</scope>
        </dependency>  
        <!-- the glue between jax-rs and json-p reference implementation -->
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-processing</artifactId>
            <version>2.17</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Now lets write our system test.

package se.magnuskkarlsson.example.javaee7.boundary;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import static javax.ws.rs.core.MediaType.*;
import javax.ws.rs.core.Response;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class EmployeeRestIT {

    private Client client;
    private WebTarget target;
    
    @Before
    public void setUp() throws Exception {
        client = ClientBuilder.newClient();
        target = client.target("http://localhost:8080/example-javaee7/rest/employee");
    }
    
    @Test
    public void crud() throws Exception {
        JsonObjectBuilder builderCreate = Json.createObjectBuilder();
        JsonObject input = builderCreate.add("name", "Foo Bar").build();
        Response respCreate = target.request(APPLICATION_JSON).post(Entity.json(input));
        assertThat(respCreate.getStatus(), is(201));
        String location = respCreate.getHeaderString("Location");
        assertNotNull(location);

        Response respGet = client.target(location).request(APPLICATION_JSON).get();
        assertThat(respGet.getStatus(), is(200));
        JsonObject payload = respGet.readEntity(JsonObject.class);
        System.out.println("payload='" + payload + "'");
        
        int id = payload.getInt("id");
        JsonObjectBuilder builderUpdate = Json.createObjectBuilder();
        JsonObject update = builderUpdate.add("id", id).add("name", "UPDATED!").build();
        Response respUpdate = target.request(APPLICATION_JSON).put(Entity.json(update));
        assertThat(respCreate.getStatus(), is(201));
        System.out.println("respUpdate=" + respUpdate.readEntity(JsonObject.class));
        
        Response respDelete = target.path("/" + id).request(APPLICATION_JSON).delete();
        assertThat(respDelete.getStatus(), is(204));
    }
    
    @Test
    public void findNonExisting() throws Exception {
        Response response = target.path("/-999").request(APPLICATION_JSON).get();
        assertThat(response.getStatus(), is(204));
        String payload = response.readEntity(String.class);
        assertThat(payload, is(""));
    }
    
    @Test
    public void findAll() throws Exception {
        Response resp = target.request(APPLICATION_JSON).get();
        assertThat(resp.getStatus(), is(200));
        JsonArray array = resp.readEntity(JsonArray.class);
        assertThat(array.size(), is(0));
    }

    @Test
    public void updateInvalid() throws Exception {
        JsonObjectBuilder builder = Json.createObjectBuilder();
        JsonObject input = builder.add("name", "E").build();
        Response response = target.request(APPLICATION_JSON).put(Entity.json(input));
        
        assertThat(response.getStatus(), is(400));
        System.out.println("status : " + response.getStatus());
        System.out.println("entity : " + response.readEntity(String.class));
        response.getHeaders().forEach((key, value) -> System.out.println(key + ": " + value));
    }
    
    @Test
    public void delete() throws Exception {
        JsonObjectBuilder builder = Json.createObjectBuilder();
        JsonObject input = builder.add("name", "Foo Bar").build();
        Response respCreate = target.request(APPLICATION_JSON).post(Entity.json(input));
        assertThat(respCreate.getStatus(), is(201));
        String location = respCreate.getHeaderString("Location");
        assertNotNull(location);
        
        Response respDelete = client.target(location).request(APPLICATION_JSON).delete();
        assertThat(respDelete.getStatus(), is(204));
    }
    
    @Test
    public void deleteNonExisting() throws Exception {
        Response respDelete = target.path("/-999").request(APPLICATION_JSON).delete();
        assertThat(respDelete.getStatus(), is(204));
    }
    
}

November 8, 2017

Java JSSE Default Truststore

"Creating an X509TrustManager

You can either implement this interface directly yourself or obtain one from a provider-based TrustManagerFactory (such as that supplied by the SunJSSE provider). You could also implement your own interface that delegates to a factory-generated trust manager. For example, you might do this to filter the resulting trust decisions and query an end-user through a graphical user interface.

Note: If a null KeyStore parameter is passed to the SunJSSE PKIX or SunX509 TrustManagerFactory, then the factory uses the following process to try to find trust material:

  1. If the javax.net.ssl.trustStore property is defined, then the TrustManagerFactory attempts to find a file using the file name specified by that system property, and uses that file for the KeyStore parameter. If thejavax.net.ssl.trustStorePassword system property is also defined, then its value is used to check the integrity of the data in the truststore before opening it.
    If the javax.net.ssl.trustStore property is defined but the specified file does not exist, then a default TrustManager using an empty keystore is created.
  2. If the javax.net.ssl.trustStore system property was not specified, then:
    • if the file java-home/lib/security/jssecacerts exists, that file is used;
    • if the file java-home/lib/security/cacerts exists, that file is used;
    • if neither of these files exists, then the SSL cipher suite is anonymous, does not perform any authentication, and thus does not need a truststore."

November 7, 2017

How to Debug an Applet or Java Web Start Application

Open Java Control Panel and select tab Advanced and enable "Enable tracing", "Enable logging" and "Show applet lifecycle exception". Apply and close web broser and open RIA, Rich Internet Applicatio, i.e. Applet or Java Web Start Application.

Your log file will be stored under $USER_HOME + File.separator + log + File.separator, on Windows that is C:\Users\your-username\AppData\LocalLow\Sun\Java\Deployment\log

To add more trace add the following to $USER_HOME + File.separator + deployment.properties, on Windows that is C:\Users\your-username\AppData\LocalLow\Sun\Java\Deployment\deployment.properties

deployment.javaws.jre.0.args=-Djava.security.debug=all -Djavax.net.debug=all
deployment.javaws.jre.1.args=-Djava.security.debug=all -Djavax.net.debug=all

Reference:
-Djava.security.debug
-Djavax.net.debug

How to unpack .jar.pack.gz

The .jar.pack.gz is a Oracle package format that can be unpacked with unpack200 binary that is shipped with the SDK.

# unpack200 your-file.jar.pack.gz your-file.jar

Reference: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/unpack200.html