Java EE 6 Web Profile. On the cloud. Easy.

Java SE is ok.

Java EE is evil.

That’s what I always used to think. Well, not anymore, now. Let me share my experience.

Some weeks ago, I started thinking about porting a legacy spring+hibernate+tomcat application to a new platform :
SAP NetWeaver Cloud. I known what you geeks out there are thinking : this post is getting worse. It starts with Java EE, not exactly a geeky thing, and now enters SAP, not exactly a geek company… Please, give me another ten minutes !

The configuration of the spring layer of my legacy application was xml-based (it was written before annotations came in the game). I was dreaded by the prospect of diving into – my own – xml horror again.

Then came this tweet :


and, some days later, this documentation. And I tried it out. And it worked. And I changed my mind about Java EE. There is a blog post by ‘Bill the Plumber’ that precisely describe what are my thoughts after this experience.

So much with the bla bla bla. Let’s start coding! If you are in a hurry, clone the complete application from https://github.com/cthiebaud/adventscloud

Before cutting and pasting like mad, let’s describe briefly what the code below is about. We will construct and deploy in the cloud (free) a tiny web application that:

1. logs in the user (sorry, you’ll need a SAP Community Network account, do not worry it’s free),

2. upon login, say ‘hello’ to the rest of the world on behalf of the user,

3. upon successive logins, instead of saying ‘hello’ again and again, merely store in a database how many ‘hellos’ were said, and

4. that’s it.

To achieve that, we’ll need one java interface, three java classes, one java server page, and a final touch of persistence.xml (for the database configuration) and web.xml (for security constraint wizardry).

For the sake of brevity, packages, imports, getters and setters are omitted from the code below. But, as just said, the complete source is available @ github

Write one Hello.java POJO (complete class here):

public class Hello {

  private Long      id;
  private String    username;
  private Integer   counter;
  private Timestamp when;
  // ... getters and setters ...
}

Fairly obvious : for each username, this POJO will store in a counter how many time the user hit the index.jsp of our app, and when was the last time.

Annotate this Hello.java POJO with JPA annotations (complete class here):

@Entity
@Table(name="T_HELLO")
@NamedQueries( {
  @NamedQuery(name = "allHellos", query = "select h from Hello h"),
  @NamedQuery(name = "helloFromUsername", query = "select h from Hello h where h.username = :username")
})
public class Hello {

  @Id
  @GeneratedValue
  private Long      id;
  @Column(name="A_USER", unique=true, nullable=false)
  private String    username;
  @Column(name="A_COUNTER", nullable=false)
  private Integer   counter;
  @Version
  @Column(name="A_TIMESTAMP", nullable=false)
  private Timestamp when;

  public Hello() {
    this.counter = 1;
  }
  // ... getters and setters ...
}

Write one HelloDao.java interface that accesses the POJO (complete interface here)

@Local
public interface HelloDao {

  List<hello> getAll();
  Hello fromUsername(String username);
  Hello save(Hello hello);
}

Write one HelloBean.java, annotated with EJB annotations, that implements the HelloDao interface (complete class here):

@Stateless
public class HelloBean implements HelloDao {

  @PersistenceContext
  private EntityManager em;

  @Override
  public List<hello> getAll() {
    @SuppressWarnings("unchecked")
    List<hello> hellos = (List<hello>)em.createNamedQuery("allHellos").getResultList();

    Collections.sort(hellos, new Comparator<hello>() {
      @Override
      public int compare(Hello o1, Hello o2) {
        return o2.getWhen().compareTo(o1.getWhen()); // latest first
      }
    });

    return hellos;
  }

  @Override
  public Hello fromUsername(String username) {
    Query query = em.createNamedQuery("helloFromUsername");
    query.setParameter("username", username);
    Hello hello = null;
    try {
      hello = (Hello)query.getSingleResult();
    } catch (NoResultException ignored) {
    }

    return hello;
  }

  @TransactionAttribute
  @Override
  public Hello save(Hello hello) {
    hello = em.merge(hello);
    return hello;
  }
}

Write one HelloFilter.java Java Servlet 3 Filter, that 1. bumps the counter upon login, and 2. exposes the HelloBean instance to the – coming soon – Java Server page (complete class here):

@WebFilter("/index.jsp")
public final class HelloFilter implements Filter {

  @EJB
  HelloDao  helloDao;

  @Override
  public void init(FilterConfig fConfig) throws ServletException {
  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  try {
    request.setAttribute("helloDao", helloDao);

    String username = ((HttpServletRequest)request).getRemoteUser();
    Hello hello = helloDao.fromUsername(username);
    if (hello == null) {
      hello = new Hello();
      hello.setUsername(username);
    } else {
      hello.setCounter(hello.getCounter()+1);
    }
    hello = helloDao.save(hello);

    chain.doFilter(request, response);

  } finally {
    request.removeAttribute("helloDao");
  }
  }

  @Override
  public void destroy() {
  }
}

NB. in bold above, the magic plumbing done by our Java EE 6 Web Profile container between all these classes :

@PersistenceContext EntityManager em;
@EJB HelloDao helloDao;
@WebFilter('/index.jsp')

Write one persistence.xml JPA configuration (complete xml here)

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="adventscloud-persist" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/DefaultDB</jta-data-source>
    <class>net.aequologica.adventscloud.Hello</class>
    <properties>
      <property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
    </properties>
  </persistence-unit>
</persistence>

Write one web.xml to trigger login when user access index.jsp and to inform the web application of the presence of a container managed database (complete xml here):

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">

  <login-config>
    <auth-method>FORM</auth-method>
  </login-config>

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Protected Area</web-resource-name>
      <url-pattern>/index.jsp</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>Everyone</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <description>All SAP NetWeaver Cloud users</description>
    <role-name>Everyone</role-name>
  </security-role>

  <resource-ref>
    <res-ref-name>jdbc/DefaultDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
  </resource-ref>

</web-app>

Again, NB. above in bold the further magic plumbing:

<jta-data-source>jdbc/DefaultDB</jta-data-source>
<class>net.aequologica.adventscloud.Hello</class>
<res-ref-name>jdbc/DefaultDB</res-ref-name>

Finally, write one index.jsp java server page that displays all ‘hellos’ (complete page here):

<%@ taglib prefix="c"   uri="http://java.sun.com/jstl/core_rt" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>
<!DOCTYPE html>
<html>
  <head>
    <title>adventscloud</title>
  </head>
  <body>

  <table>
    <tbody>
      <c:forEach var="hello" items="${requestScope.helloDao.all}" varStatus="status">
        <tr>
          <td><fmt:formatDate type="both" value="${hello.when}" /></td>
          <td>${hello.counter}</td>
          <td>hello<c:if test = "${hello.counter > 1}">(s)</c:if> from</td>
          <td>${hello.username}</td>
        </tr>
      </c:forEach>
    </tbody>
  </table>  

  </body>

</html>

We’re nearly done … two last things: 1. classpath hell, and 2. JPA 2.0 metamodel generation with javac -processor.

1. Classpath hell.

In order to compile all this stuff, you’ll need somehow to have the following jars on the classpath :

group | artifact | version
javax.persistence : persistence-api   : >= 1.0 
javax.ejb         : ejb-api           : >= 3.0 
javax.servlet     : javax.servlet-api : >= 3.0 
javax.servlet     : jstl : >= 1.2

Of course the easiest way is to declare these dependencies in a maven project like mine, but if you are maven-averse, I took the time to hyperlink to the jars above to maven central to spare you some time chasing the jars.

2. JPA 2.0 metamodel generation with javac -processor.

Finally , the build must be able to generate JPA 2.0 metamodel classes. Here I choose the eclipselink generator, as eventually eclipselink is the JPA implementation used by SAP NetWeaver Cloud. I believe that any JPA 2.0 compliant generator should do the job as well. Here also, maven do help, with the following xml fragment in the <build><plugins> section of the pom.xml:

<plugin>
  <groupId>org.bsc.maven</groupId>
  <artifactId>maven-processor-plugin</artifactId>
  <version>2.1.0</version>
  <executions>
    <execution>
      <id>process</id>
      <goals>
         <goal>process</goal>
      </goals>
      <phase>generate-sources</phase>
      <configuration>
        <processors>
          <processor>org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor</processor>
        </processors>
      </configuration>
    </execution>
  </executions>
</plugin>

Maven-averse can refer to eclipselink documentation about JPA 2.0 matamodel generation for alternative means to generate JPA 2.0 metamodel classes.

At this point, we have a adventscloud.war file that should run verbatim on any Java EE 6 Web Profile compliant container.

Among them is SAP NetWeaver Cloud. You can have a look at the application running at my lifelong-free trial instance of SAP NetWeaver Cloud. It is a bit richer than the code shown in this blog post, with a spark of twitter bootstrap bells and whistles. Follow the github ribbon in the app if you are interested by sparks.

If you’d like to get your lifelong-free trial instance of SAP NetWeaver Cloud, follow the initial steps described here.

 

Reference: Java EE 6 Web Profile. On the cloud. Easy. from our JCG partner Christophe Thiebaud at the Java Advent Calendar blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


3 − two =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close