Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1090 lines (845 sloc) 24.1 KB

6 5 tips for you JavaEE project be less depresing

Does JavaEE have to be so depressing?

[square o] Why this talk?

[square o] 5 tips to make your JavaEE live better

Note
  • These are things to cover

  • Why this talk?

    • Why did I eve though about going beyond JavaEE while still staying with JavaEE

Who am I?

Jakub Marchwicki
  Twitter: <@kubem>
  Email: jakub@marchwicki.pl

Coder, trainer, speaker
Past life: management, architecture
  http://jakub.marchwicki.pl
  Yes, we can work together!
Note
  • This talk is based on my training / consultancy experience

  • Where I help JavaEE teams fully embrance the spec

  • Recover from existing systems

Does JavaEE have to be so depressing?

[square o] Why this talk?

[square o] 5 tips to make your JavaEE live better

We’ve chosen JavaEE to build our start-up!

No one ever

Note
  • Ok, I know there can be some

  • Most of the teams I’ve met didn’t choose the technology

  • It was there long before them

    • And will probably outlive them as well

  • There is a decent amount of patterns, templates within the organisation, which hardly ever get re-evalated

This is the way we do things

because we’ve always did it like that

Note
  • That’s how legacy get created, where existing patterns are not questions

  • That’s where people start to hate technology

    • They are slapped in the face with "standards"

Company Standards

aka Cargo Cult

Multiple modules build

All projects need to be structured same way

<modules>
  <module>customer-data-service-wsdls</module> (1)
  <module>customer-data-service-services</module> (2)
  <module>customer-data-service-web</module> (3)
  <module>customer-data-service-client</module> (4)
</modules>
  1. Just the WSDL file

  2. This contains everything (entities, services)

  3. A single @WebService

  4. Generated webservice stub (client)

Note
  • 23 java files, 4000 lines of code

  • And the project is maintaned by a single person

  • Other structured get refused by the operations

    • You’ve heard about ivory tower antipattern

  • I’m not saying it’s inherently bad

    • I can work in some contexts

    • In most they don’t

What am I doing?

/**Thread for SOAPConnection */
SOAPConnectionThread soapConnectionThread = new SOAPConnectionThread();
soapConnectionThread.start();
try {
  soapConnectionThread.join( soapJoinTime );
} catch ( InterruptedException ie ) {
  errorLog = errorLog + "soapConnectionThread InterruptedException: " +
    ie.getMessage() +
    conversion.getExceptionTrace(ie,StaticVariables.getStackTraceLength()) + "; ";
} catch ( Exception e ) {
  errorLog = errorLog + "soapConnectionThread Exception: " + e.getMessage() +
    conversion.getExceptionTrace(e,StaticVariables.getStackTraceLength()) + "; ";
}
Note
  • What some more?

What am I doing? #2

if (successfulSOAP) {
  soapMsg = soapConnectionThread.getSOAPMessage();
  if (soapMsg.indexOf("<faultcode>") == -1
    && soapMsg.indexOf("</faultcode>") == -1
    && soapMsg.indexOf("<faultcode/>") == -1
    && soapMsg.indexOf("<faultstring>") == -1
    && soapMsg.indexOf("</faultstring>") == -1
    && soapMsg.indexOf("<faultstring/>") == -1) {
    //...some business logic
  } else {
    errorLog = errorLog +
      "Exception in call to ProdRefreshWS or connection timeout (timeout=" +
       StaticVariables.getConnectionTimeout() +
       "ms; targetURL=" + targetURL + ")" + "; ";
    extCallDuration =  extCallDuration + ":prodRefWS_except:" +
      String.valueOf(soapEndTime.getTime() - soapStartTime.getTime());
    soapConnectionThread.stop();
  }
}
Note
  • It’s easy to bash bad programmers

  • I’m showing these examples because this is how most people is thinking about JavaEE

    • But it doesn’t need to be like this

We need to win JavaEE back cause there is lots of bad bad code out there

New is always better

  • What do engineers do when a technology (they don’t know)
    doesn’t work for them?

  • …​

  • …​

  • …​

  • Change the technology

Note
  • I’ve seen that pattern multiple time

  • JavaEE doesn’t work for us

    • But we really didn’t understand it

  • So the team jumps new bandwagon - which they didn’t get either

Let’s rebuild it in Spring!

And now we have two problems

This is a real life stack

  • WebLogic 12.1.3

    • JavaEE7 compliant (JAXRS 2.0, JPA 2.1, websockets)

  • Spring 3.2.6

Note
  • It was 2015! Spring 4 was announced December 2013.

    • I bet it was mature enough

  • Weblogic, which the team don’t understand

  • Spring on the top of that - which the team didn’t get either

    • But it looked good on Linked In!

I have a picture for that

Note

We need to win JavaEE back cause it’s not that bad afterall

Does JavaEE have to be so depressing?

[check square o] Why this talk?

[square o] 5 tips to make your JavaEE live better

  • Know your stack

  • The Standard won’t save you (aka Your Vendor is your framework)

  • Limit the boiler plate

  • Go beyond The Standard (not only JPA)

  • Don’t be limited to server-side MVC

Note
  • New weblogic with apache attic dependencies

  • Won’t standard save us by itself?

  • Because good talk won’t work without a rant

  • Deltaspike: Be more like Spring, like Spring-data

  • jDBI, JOOQ: Be more like glue layer, not very opinionaned

  • Web without JSF

1 of 5 tips

#1 Know your stack

…​ better over the years

The enterprise bean must not attempt to manage threads. The enterprise bean must not attempt to start, stop, suspend, or resume a thread, or to change a thread’s priority or name. The enterprise bean must not attempt to manage thread groups.

— EJB Spec - 21.2.2. Programming restrictions

…​ better over the years

@Singleton
public class JobProcessor {

  @Asynchronous (1)
  public Future<String> addJob(String jobName) {

      // Pretend this job takes a while
      doSomeHeavyLifting();

      // Return our result
      return new AsyncResult<String>(jobName);
  }
}

…​ better over the years

@Stateless
public class MyBean {

    @Resource
    ManagedExecutorService managedExecutorService; (2)

    public void executeAsync() throws ExecutionException, InterruptedException {
        for(int i=0; i<10; i++) {
            MyTask myTask = myTaskInstance.get();
            managedExecutorService.submit(myTask);
        }
    }
}
Note
  • JMS for internal communication became obsolete and antipattern

…​ better over the years

import javax.inject.Inject;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named (3)
@RequestScoped (4)
public class Printer {

    @Inject @Informal Greeting greeting; (5)

    //...
}

…​ better over the years

@Named
public class HelloMessenger {

    @Inject Event<HelloEvent> events; (6)

    public void hello(){
        events.fire(new HelloEvent("from bean " + System.currentTimeMillis()));
    }
}
@Named
public class HelloListener {
    public void listenToHello(@Observes HelloEvent helloEvent) { (7)
        System.out.println("HelloEvent: " + helloEvent);
    }
}
Note

If you attend tomorrow a session by Ondrej Mihályi about reactive - these exact features are used for JavaEE to pretend to be reactive (and pretend pretty nice - may people gets fooled)

It’s kind of OK

But it’s still not Spring
  • Database is like opinion, everyone’s different

    • JDBCTemplate (lightweight persistence)

    • Spring-data (everything by convention)

  • Spring-whatever-framework-I’d-like-to-integrate

    • JSP / JSF and beyond

2 of 5 tips

#2 Your Vendor is your framework

But it’s all about The Standard

<dependency>
  <groupId>javax</groupId>
  <artifactId>javaee-api</artifactId>
  <version>7.0</version>
  <scope>provided</scope>
</dependency>
Note
  • whose dependencies sumup to this artifact?

    • that should be enough for the business logic

Spring vs JavaEE

Spring

Single vendor; not standardized - but changes and differences are manageable

JavaEE

Multiple Vendors; interpretation subject to change

Not so really injection standard

Not so really injection standard

public interface Service {
  public String hello();
}
@Stateless
public class MyService implements Service {
  public String hello() {
    return "Hello world!"
  }
}
@Stateless
public class MyOtherService implements Service {
  public String hello() {
    return "Hello Voxxed!"
  }
}

Not so really injection standard

@Startup
@Singleton
public class Client {

  @EJB Service service; (1)

  @PostConstruct
  public void init() {
    System.out.println(service.hello());
  }
}
Note
  • So what’s get printed?

  • It depends

    • OpenEJB - takes the last deployed

    • JBoss / Wildfly family - throws error

Not so really injection standard

@Startup
@Singleton
public class Client {

  @Inject Service service; (2)

  @PostConstruct
  public void init() {
    System.out.println(service.hello());
  }
}
Note
  • What is we change just on line?

  • CDI kicks in - error

    • CDI was supposed to solve this problem

    • Unless it didn’t

Not so really injection standard

In case of some versions of Weld (or OpenWebBeans), you have to configure it as a global alternative instead of an alternative in beans.xml.
— Apache DeltaSpike documentation
Note

So we have a standard but still we are not there yet

After all it’s a standard

<dependency>
    <groupId>org.apache.tomee</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.jboss.spec</groupId>
    <artifactId>jboss-javaee-7.0</artifactId>
    <version>1.0.0.Final</version>
    <scope>provided</scope>
</dependency>
Note
  • This is a popular rant

    • But no one really care

  • We just usually glue ourselves to a single application server

    • And treat it as a single vendor

  • And that way our JavaEE is becoming like Spring - not being Spring

  • So we don’t have much advantage from "following the standard"

  • But we loose a lot in terms of the Spring fanciness and flexibility

Just accept it and move forward

3 of 5 tips

#3 Limit the boiler plate

Meet Apache DeltaSpike

  • A set of CDI extensions

  • Working on a number of CDI implementations and application servers

    • From Tomcat / TomEE, through JBoss / Wildfly to Weblogic

  • Adds some JavaEE flavour to context containers

    • Transactions

    • Servlet injection

  • Adds some of the JavaEE missing parts

    • Context aware Bean Validation

    • Easier scheduling (with Quartz)

Note
  • ConstaintValidation injection

  • If you’ve ever tried working with Quartz - these guys really made it easy

DeltaSpike Data

  • Like Spring Data but without Spring

  • Reduces JPA boilerplate to bare minimum

    • Provides implementation of repository pattern for simple queries

    • 'Clutter methods' like save, findAll, findBy

  • Provides conventions for repository methods findByNameLikeAndAgeBetweenAndGender

  • Works with JPQL queries and @NamedQueries

  • Allows pagination, bulk operations and optional results

Note
  • This is something I focused on in most of my projects

  • There is too much boilerplate in typical 'business applications'

    • CRUD operations in your financial applications

DeltaSpike Data vs Spring Data

import org.apache.deltaspike.data.api.EntityRepository;

@Repository
public interface PersonRepository extends EntityRepository<Person, Long> {
    List<Person> findByAgeBetweenAndGender(int minAge, int maxAge, Gender gender);

    @Query("select p from Person p where p.ssn = ?1")
    Person findBySSN(String ssn);
    @Query(named=Person.BY_FULL_NAME)
    Person findByFullName(String firstName, String lastName);
}
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
  List<User> findByLastname(String lastname);

  @Query("select u from User u where u.emailAddress = ?1")
  User findByEmailAddress(String emailAddress);
}

Problems?

Never (totally) trust the generated code

  • Start with just implementing EntityRepository
    if you need a repository layer at all

  • Declare simple queries with query derivation mechanism (parsing)
    or manual queries

  • For more complex queries, add your own query methods to repository

Note
  • For Spring Data named queries comes by convention - through method name

CDI Producer methods

Producer method generates an object that can then be injected

  • Introduced as a part of JavaEE 6 (JSR-299)

  • Prescribes:

    • Contexts - bindable lifecycle of components

    • Dependency injection - typesafe injection of components

Note
  • Essential part of this element is CDI

  • It was an enabler of what we will be talking later on

CDI Producer methods

When concrete type of the object to be injected may vary at runtime

@Produces
public Coder getCoder() {

    switch (coderType) {
        case TEST:
            return new TestCoder();
        case SHIFT:
            return new DefaultCoder();
        default:
            throw new CoderNotAvailableException();
    }
}
@Inject Coder coder;

CDI Producer methods

When object requires some custom initialization

@ApplicationScoped
public class EntityManagerProducer {

    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    @Produces
    public EntityManager create() { (1)
        return this.entityManagerFactory.createEntityManager();
    }

    public void dispose(@Disposes EntityManager entityManager) {
        if (entityManager.isOpen()) {
            entityManager.close();
        }
    }
}
  1. Cannot be performed by the bean constructor

4 of 5 tips

#4 Go beyond The Standard (not only JPA)

Persistence without JPA

select event_type,
  date_format(`date`, '%Y-%m-%d %H:%i') AS formatted_date,
  avg(timing) as avg_duration,
  group_concat(DISTINCT el.uuid) as uuids,
  group_concat(DISTINCT wl.todo_id ORDER BY todo_id ASC) as todo_ids,
  count(1) as count
from event_log el
  LEFT JOIN write_log wl ON el.uuid = wl.uuid
  GROUP BY event_type, minute(date)
  ORDER BY formatted_date asc
Note
  • if we got more complitated query - were JPA just gives up

  • joins, groups, specific SQL functions

    • we have JPA NativeQuery

    • or use something totally different

JDBI configuration

When needed to inject an object that is not a bean

@ApplicationScoped
public class JDBIConfiguration {

    @Resource
    DataSource dataSource;

    @Produces
    public EventsPerMinuteDao createEventPerMinuteDao() {
        DBI dbi = new DBI(dataSource);
        return dbi.onDemand(EventsPerMinuteDao.class);
    }

    public void dispose(@Disposes EventsPerMinuteDao dao) {
        dao.close();
    }
}

JDBI Dao

public interface EventsPerMinuteDao {

    @SqlQuery("select event_type, " +
            "  date_format(`date`, '%Y-%m-%d %H:%i') AS formatted_date, " +
            "  avg(timing) as avg_duration, " +
            "  group_concat(DISTINCT el.uuid) as uuids, " +
            "  group_concat(DISTINCT wl.todo_id ORDER BY todo_id ASC) as todo_ids, " +
            "  count(1) as count " +
            "from event_log el" +
            "  LEFT JOIN write_log wl ON el.uuid = wl.uuid " +
            "  GROUP BY event_type, minute(date) " +
            "  ORDER BY formatted_date asc ")
    @Mapper(EventsPerMinuteMapper.class)
    List<EventsPerMinute> listEventsPerMinute();

    void close();
}
@Inject EventsPerMinuteDao eventsDao;

JOOQ configuration

@ApplicationScoped
public class JooqDslContextProducer {

    @Resource
    DataSource dataSource;

    @Produces
    @Default
    public DSLContext jooq() {
        return DSL.using(dataSource, SQLDialect.MYSQL);
    }
}
Note
  • This is the feature we will be using

  • This allows us to easily integrate 3rd party libraries our application

  • As well as building JavaEE dedicated libraries aiming the complexity - like DeltaSpike

5 of 5 tips

#5 Don’t be limited to server-side MVC

Web development #1 anti-pattern

Never let backend engineers develop frontend UI

Note
  • There is one

  • Especially if that’s something to be seen by customer, business

  • JSP / JSF environment wasn’t natural for neither web developers nor backend engineers.

  • The outcome was crappy html code

Designers are pixel perfect beasts

zeplin measurements
Note
  • Designers are pixel perfect - backend engineers are not

  • For backend guys - this is totally unnatural, out of the comfort zone

  • But when we do web with JSP / JSF - we are forced to do so

Problems with JSP / JSF

  • Relatively steep learning curve (compare to LAMP stack)

  • Always outside of the modern web stack hype circle

  • JSP / Servlet approach is too simple (even simplistic)

  • JSF is (was) overcomplicated - and a bit against the nature of the web

  • No fined grained control over HTML / CSS / JS in component based JSF

  • Nothing in between (so far) - lightweight MVC framework

Note
  • Huuge learning curve. JSF is complex, that’s just true.

  • Loads of boiler plate code for JSP / Servlet approach

  • JSF Its component nature

    • hide the true nature of the Web, work against the web (not supporting GET in JSF within almost 5 years)

    • hiding Request/Response from the developer is an enormous mistake

  • It’s great JSF 2.2 caught up with most of the problems it used to have - but the web is somewhere else at the moment

    • I know JSF 2.x is to 1.x like EJB 3.x to 2.x - but still

Approach #1

Try JavaEE8 MVC 1.0 (Ozark)

with some template engine like Thymeleaf or Freemarker or Mustache

Approach #1

Try JavaEE8 MVC 1.0 (Orazk)

with some template engine like Thymeleaf or Freemarker or Mustache

Approach #1

CDI extension for Stateless MVC framework

hack Struts2 with JavaEE

Note

Why hack

  • it does not integrate smoothly, you cannot simple inject your service into struts actions without InitialContext and lookups

Approach #1

Maybe JSF 2.3 will bring any good

(…​) more as the default MVC framework in Java EE and less as an out of the box standalone MVC framework for Tomcat. Examples are ditching its own managed bean model, its own DI system, and its own expression language.

Approach #1

Try JavaEE8 MVC 1.0 (Orazk)

CDI extension for Stateless MVC framework

Maybe JSF 2.3 will bring any good

Note

Non of those are my go-to choices. But it can be just me

Approach #2

Leave the frontend to web developers

and their stack

Modern frontend stack

NodeJS + NPM

Bower

Some other build tools

Note
  • Let them play with it on their own

    • Backend / frontend separation

    • With mocked backend in expressjs

  • Just let them leave your pom.xml in their project

Let them play their toys

  "devDependencies": {
    "bower": "^1"
  }
  "dependencies": {
    "jquery": "1.9.1",
    "backbone": "1.0.0",
    "underscore": "1.4.4"
  }

Maven for the rescue

Spanish Inquisition

frontend-maven-plugin

<plugin>
  <groupId>com.github.eirslett</groupId>
  <artifactId>frontend-maven-plugin</artifactId> (1)
  <version>0.0.27</version>
  <configuration>
    <installDirectory>target</installDirectory>
  </configuration>
  <executions>
    <execution>
      <id>install node and npm</id>
      <!-- omitted for brevity -->
    </execution>
    <execution>
      <id>npm install</id>
    </execution>
  </executions>
</plugin>

maven-resources-plugin

<plugin>
  <artifactId>maven-resources-plugin</artifactId> (2)
  <version>2.7</version>
  <executions>
    <execution>
      <id>copy-resources</id>
      <configuration>
        <outputDirectory>${basedir}/target/classes/META-INF/resources</outputDirectory>
        <resources>
          <resource>
            <directory>app/</directory>
          </resource>
        </resources>
      </configuration>
    </execution>
  </executions>
</plugin>

Output JAR file

META-INF
└── resources
    ├── bower_components (1)
    │   ├── backbone
    │   ├── jquery
    │   └── underscore
    ├── components
    ├── js (2)
    │   ├── models
    │   ├── routers
    │   ├── views
    │   └── app.js
    └── index.html (3)
  1. Components downloaded by Bower

  2. Backbone applications

  3. Main HTMl page

Servlet 3.0 injection

  • What was created in the previous step is actually a WebJar

    • A client-side web library packaged into JAR (Java Archive) file

  • Servlet 3.0 specification prescribes way to server static assets from Jar files

    • the WebJars that are in the WEB-INF/lib directory are automatically made available as static resources

    • this works because anything in a META-INF/resources directory in a JAR in WEB-INF/lib is automatically exposed as a static resource.

  • The WebJar needs to be a dependency of the application

Maven dependency

<dependencies>
    <dependency>
        <groupId>com.example.foo</groupId>
        <artifactId>npm-based-web-application</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

The 5 TIPS for JavaEE to be less depressing

[check square o] Why this talk?

[check square o] 5 tips to make your JavaEE live better

  • Know your stack

  • The Standard won’t save you (aka Your Vendor is your framework)

  • Limit the boiler plate

  • Go beyond The Standard (not only JPA)

  • Don’t be limited to server-side MVC

Note
  • Latest JavaEE

  • Take advantage of your server

  • With tools like DeltaSpike

  • jOOQ, jDBI

  • NPM, modern MVC

Questions?

Note
  • which I’m happy to take while browsing through code showing how it’s constructed

Follow me on twitter
  Twitter: <@kubem>
  Email: jakub@marchwicki.pl

Want a free ebook from Packt - visit @dailyfreeebook

This presentation was made with AsciiDoc
Presentation source and examples
  https://github.com/kubamarchwicki/winning-javavee-back
  -- including links

Some inspirations from Dan Allen (@mojavelinux)
  http://mojavelinux.github.io/decks/zen-of-writing-asciidoctor/devnexus2015/