Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Adam Bien on Lightweight JEE

Adam Bien on Lightweight JEE

More Decks by Enterprise Java User Group Austria

Other Decks in Technology

Transcript

  1. blog.adam-bien.com Introduction Expert Group Member (jcp.org) of Java EE 6,

    EJB 3.1, Time and Date and JPA 2.0 Java Champion,Netbeans Dream Team Member, (JavaONE) speaker, freelancer, consultant and author: 7 German books + working on “Real World Java EE Patterns– Rethinking Best Practices” http://press.adam-bien.com Trainer, Developer and Architect (since JDK 1.0) Project owner/committer: http://kenai.com/projects/javaee-patterns, greenfire.dev.java.net, p4j5.dev.java.net, fishfarm.dev.java.net
  2. blog.adam-bien.com EJBs Are Heavyweight Configuration is mainly gone, because of

    conventions... (there was no XML in my last projects except persistence.xml) EJB 3 are just annotated Java classes (if you love XML you can even use just Deployment Descriptors instead of annotation) Container “services” like transactions, security, concurrency or state are implemented with aspects (often realized with dynamic proxies)
  3. blog.adam-bien.com EJBs Are Heavyweight "POJOs" are just JavaBeans maintained by

    another container, using similar techniques as EJB 3.1 EJB 3 containers are surprisingly small. Glassfish v3 EA comes with two jars (688kB + 8kB = 696kB). The EJB 3 container is an OSGI bundle... The whole EJB 3.1 API is about 47 kB.
  4. blog.adam-bien.com EJBs Are Hard To Test To test your EJBs

    outside the container, you will need to have the EJB 3.1 annotations available in your classpath. In recent projects we deployed EJB 3.0 components directly to Eclipse / Netbeans RCP application. We could start and test the application without even having an application server involved. If you can start EJBs outside the container, you can start them in a unit test as well...
  5. blog.adam-bien.com EJBs Are Hard To Test Create the EntityManager and

    fetch the EntityTransaction in the superclass...
  6. blog.adam-bien.com EJBs Are Hard To Test ...inherit from it. Just

    inject / mock the dependencies by hand (EJB 3.0)
  7. blog.adam-bien.com EJBs Are Hard To Test EJB 3.0 are just

    annotated POJOs - you can test them as such. Transaction / Security can be harder to test - but integration tests are better for that purpose. In EJB 3.1 the testing experience is even better with:
  8. blog.adam-bien.com EJBs Are Not Portable J2EE 1.4 was underspecified :-)

    - EJB 3.X / JPA specs cover more real world stuff (locking, optimistic concurrency etc.). Vendor specific deployment descriptor were painful for migration - they are basically gone. In most cases a EJB-JAR module is nothing but a JAR without any XML descriptors (neither ejb-jar.xml nor vendor specific) Vendor specific annotations are not needed to develop a Java EE application. There is NOTHING vendor specific in an EAR. The portability is really good.
  9. blog.adam-bien.com EJBs Are Not Extensible Interceptors are able to access

    the Bean instance directly. Having an instance available - you can manipulate it; inject members use reflection to invoke methods, or set fields... It is very interesting for the integration of existing “legacy” IoC frameworks :-)
  10. blog.adam-bien.com EJBs Are Slow The throughput of the EJB 3

    solution was 2391 transactions/second. The slowest method call took 7 milliseconds. The average wasn't measurable. Please keep in mind that in every request two session beans were involved - so the overhead is doubled. POJO: The throughput of the POJO solution was 2562 requests/second (request - there are no transactions here). The slowest method call took 10 ms. The difference is 171 requests / seconds, or 6.6% (therefore 3.3% for a single session bean).
  11. blog.adam-bien.com EJBs Are Not Scalable EJB (1.0, 1.1, 2.0, 2.1,

    3.0 and 3.1) are always executed in a dedicated thread - they appear as single threaded for the developer. For every thread (=user request, transaction) a new EJB instance is created (or reused from pool) - there is actually no shared state, except you access singletons, files etc. - which is not allowed. Actually the spec even prohibits the usage of the synchronization primitives and threading functionality inside EJBs.
  12. blog.adam-bien.com EJBs Are Not Scalable Furthermore the programming model is

    rather procedural (or if you will "service oriented") - so in the @Stateless Session Beans the methods process some input data and give it back to the caller. Even the @Stateful Session Beans do not brake the rule - the container still prohibits concurrent access to the @Stateful instance. Because a @Stateful Session Bean can be only executed in a single thread - you do not have (you shouldn't!) care about the threading either.
  13. blog.adam-bien.com EJBs Are Not Scalable If you acess the JPA-persistence

    - the container synchronizes the data for you. Every transaction receives a copy of the JPA-entity (it is often implemented in this way), so nothing bad can happen even in this case. Every thread is (hopefully) executed in a single core. So if you keep the transactions short, and do not "hack" the EJBs accessing static variables or singletons - you are on the bright side :-).
  14. blog.adam-bien.com EJBs Are Not Scalable Every bean is executed in

    a (pooled) thread. Bean instances are bound to the thread for the duration of the execution. Load balancing works perfectly - you can start as many servers as you like to. Even without having a cluster... For SFSB “session affinity” can improve the scaleability significantly. Programming restrictions do encourage “functional programming” (no shared state, blocking, threads)
  15. blog.adam-bien.com EJBs Are Not Scalable (some load test results) Environment:

    Glassfish v2ur2 on Linux, Clustered, a 4 way, Intel based machine and JDK 1.5 (JDK 1.6 would be better, but was not available in this case). Two load-generators ran remotely (via IIOP, standard EJB 3 client), each with 50 virtual users. Settings: -Xmx to 512m: no further tuning was performed. Configuration: CRUD application as load generator, without think-time, and almost empty database, just to stress the appserver as much as possible. Result: 250 - 500 Transactions / second (we weren't alone on the machine :-().
  16. blog.adam-bien.com EJBs Are Too Complex Java EE is distributed and

    concurrent platform per definition. It mainly abstracts already existing products (messaging, EIS, relational databases) Distributed programming with shared state is always a challenge. In the Cloud Computing / SOA era non-functional requirements like: monitoring (JMX), management, fail- over or elasticity become more and more important. Think about the ratio between the essential and accidential complexity...
  17. blog.adam-bien.com DI in Wicket Configuration in Wicket application required: import

    org.wicketstuff.javaee.injection.JavaEEComponentInjector; import org.apache.wicket.protocol.http.WebApplication; public class WicketApplication extends WebApplication{ @Override protected void init() { addComponentInstantiationListener( new JavaEEComponentInjector(this)); } }
  18. blog.adam-bien.com DI in Wicket …then EJB 3.X can be just

    injected into pages: import org.apache.wicket.markup.html.WebPage; public class ProfileView extends WebPage { @EJB(name = "profileService") private ProfileService profileService; @EJB(name = "dealerService") private DealerService dealerService;
  19. blog.adam-bien.com JSF EJB 3 injection is even easier: 1. No

    additional declaration in web.xml 2. No programmatic configuration needed. 3. Just inject SLSB into request-scoped and SFSB into session-scoped backing beans public class StatefulBackingBean{ @EJB private OrderGateway orderGateway; }
  20. blog.adam-bien.com Servlets Same story as in JSF: 1. No additional

    declaration in web.xml 2. No programmatic configuration needed. 3. Just inject SLSB into the servlet and lookup SFSB and put them into the HTTPSession public class LoadServlet extends HttpServlet{ @EJB private PersonService service; }
  21. blog.adam-bien.com Servlets Servlets can be used to implement simple load

    test scenarios for the EJB layer: • Inject your bean into the servlet • Implement the test-flow in doGet method • Use e.g. http://jakarta.apache.org/jmeter to generate the load • Use JConsole / VisualVM to monitor server • Watch the resource consumption and throughput.
  22. blog.adam-bien.com Legacy POJO injection • Not everything is an EJB

    • Sometimes it is convenient to inject „legacy POJOs“ • But we do not always have the source for the legacy POJO…
  23. blog.adam-bien.com EJBs Are Hard To Configure EJB 3.0 Session Beans

    can be configured using XML in different ways. You can use dependency injection, as well as programmatic lookup for this purpose. The dependency injection approach allows you the definition of default values in the bean class, which can be overwritten in the deployment descriptor (the XML- file).
  24. blog.adam-bien.com EJBs Are Hard To Configure The ejb-jar.xml isn’t beautiful

    - but portable. The verbose syntax will improve in EJB 3.1 Think about the Guice integration - there are no limits here...
  25. blog.adam-bien.com EJBs Are Hard To Migrate EJB 3 are compatible

    with EJB 2 You can deploy EJB 2 beans as EJB 3 You can then inject EJB 2 instances straight into EJB 3 After this step you can just delete the XML etc. Is up to you, whether you would like to delete the superfluous artifacts like home-, remote interfaces. XML deployment descriptors are no more needed after the migration...
  26. blog.adam-bien.com EJBs Are Hard To Develop Simplest possible EJB 3.1:

    @Stateless public class SimpleSample{ public void doSomething() { /*business logic*/ } }
  27. blog.adam-bien.com EJBs Are Hard To Develop How to compile: You

    will need the the EJB 3.0 / 3.1 API in the classpath, or at least the @Stateless annotation. How to deploy: Just JAR the class and put the JAR into e.g: [glassfishv3-prelude- b23]\glassfish\domains\domain1\autodeploy How to use: import javax.ejb.EJB; public class MyServlet extends HttpServlet{ @EJB private SimpleSample sample; }
  28. blog.adam-bien.com SBA / PS The crucial artifact in any SOA

    is an exposed service. A service is a contract with significant business value. A clear relationship should exist between the service contract and a business requirement, a use case, or even a user story. A service can be realized as a single action or a set of cohesive actions. A service might comprise a single action that performs the actual order, or a group of related operations that also include canceling the order and receiving the order status
  29. blog.adam-bien.com SBA / PS A SOA does not reveal any

    details about how a service must be implemented; it aims for services to be technology- and even location-agnostic. Whether the service is local or remote, the business logic should always be executed consistently. A component needs a dedicated remoting and transaction boundary interface, which acts as a gatekeeper. The main responsibility of such a facade is to keep the granularity of the methods coarse and the persistent state of the component consistent.
  30. blog.adam-bien.com Transaction / Remoting Boundary A dedicated boundary is nice

    for: Transactions Remoting (REST, IIOP, RMI and probably SOAP) Integration Testing Decoration / Aspects Contract Documentation Monitoring Unit Testing Quality assurance / maintenance
  31. blog.adam-bien.com ...where is the business logic Boundaries do not implement

    business logic, rather than realize the “flow”. Boundaries are coordinators. Services do implement business logic and are exposed with the Boundary (ServiceFacade). Boundaries makes the Services coarser.
  32. blog.adam-bien.com Service The intention of a service is straightforward --

    it is the realization of the business logic. In the SOA world it has rather procedural nature. A service resides behind the facade, so it can never be accessed directly by the UI or other presentation components. A service is stateless and can be only called by the facade. Every facade's method starts a new transaction, so a service can safely rely on the transactions' existence.
  33. blog.adam-bien.com Service The context changed in Java EE quite a

    bit. A Service is a procedural activity. It realizes activities or sub processes. In an object oriented, domain driven context, a Service realizes cross cutting, domain object independent logic. In a SOA a Service plays the main role and implements the actual business logic.
  34. blog.adam-bien.com Service (Conventions) A Service is a local, stateless session

    bean. Service resides in a component which is realized as Java- package with domain-specific name e.g. ordermgmt. The realization of the service (business interface and the bean implementation) resides in a sub-package with the name “service” e.g. ordermgmt.service. This makes the automatic verification of the architecture easier. The business interface is named after business concepts, without the obligatory local or remote suffix e.g. OrderService and OrderServiceBean.
  35. blog.adam-bien.com Service (Solution) A Service is always local and comes

    with the TransactionAttributeType.MANDATORY transaction attribute: @Stateless @TransactionAttribute(MANDATORY) public class Service{ }
  36. blog.adam-bien.com ...the persistent state Services contain (procedural) business logic, but

    are transient. Service Facades (boundaries) are transient either. Entities do contain persistent state, but no business logic (procedural again). Entity are actually not objects, rather than structs. Entities are manipulated by Services, sometimes Service Facades.
  37. blog.adam-bien.com Entity Control Boundary The “lightweight” way to design applications:

    Entity: persistent object (“domain objects” from conceptual model) Control: process knowledge - entity independent logic, the glue between the boundary and the entity Boundary: the interface between the actor and the use case
  38. blog.adam-bien.com Boundary / Service Facade package ...bookstore.business.ordermgmt.boundary; @Stateless @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) //

    optional public class OrderServiceBean{ @EJB private CrudService crudService; @EJB private VatCalculator vatCalculator; @EJB private PriceCalculator pc; @EJB private OrderProcessor op; @EJB private ShipmentService shipmentService; public Shipment orderBook(int customerId,int isbn){ BigDecimal priceNoVat = this.pc.computePrice(customerId, isbn); BigDecimal price = this.vatCalculator.computeVat(priceNoVat); Order o = this.op.processOrder(customerId, customerId, price); return this.shipmentService.deliver(o); } //more methods }
  39. blog.adam-bien.com The Entity @Entity @Table(name="T_ORDER") @NamedQuery(name=Order.findByCustomerId,query="SELECT o FROM Order o

    where o.customerId = :customerId") public class Order { public final static String PREFIX ="..ordermgmt.domain.Order"; public final static String findByCustomerId = PREFIX + "findByCustomerId"; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private int customerId; //millions of getters/setters :-) }
  40. blog.adam-bien.com The Control (Service) @Stateless @TransactionAttribute(TransactionAttributeType.MANDATORY) public class OrderProcessor {

    @PersistenceContext EntityManager em; public Order processOrder(int customerId, int productId, float price) { Order order = new Order(customerId, productId, price); em.persist(order); return order; } }
  41. blog.adam-bien.com A lightweight, RESTFul EJB 3.1 @Stateless @Path("current") public class

    ServiceFacade { @EJB Service service; @GET public String getDate(){ return service.getCurrentDate().toString(); }
  42. blog.adam-bien.com Domain Driven Design Domain-driven design (DDD) is an approach

    to the design of software, based on the two premises that complex domain designs should be based on a model, and that, for most software projects, the primary focus should be on the domain and domain logic (as opposed to being the particular technology used to implement the system).
  43. blog.adam-bien.com Domain Driven Design The idea: The domain model should

    form a common language given by domain experts for describing system requirements, that works equally well for the business users or sponsors and for the software developers.
  44. blog.adam-bien.com Gateway A perfect anti-”Service Facade” Exposed the Domain Objects

    Directly Stateful Local (should be accessed “per reference”) Its lifecycle depends on the web components Realizes only domain object independent logic and cross cutting aspects
  45. blog.adam-bien.com Gateway A @Stateful Session Bean Works only with @Local

    views No-interface view is sufficient Often caches the root entity - plays the role of Domain Repository Controls transactions Implements queries and basic CRUD operations Is accessed directly by the UI
  46. blog.adam-bien.com Gateway PDOs are already consistent, encapsulated objects with hidden

    state. There is no need for further encapsulation – they can be directly exposed to the presentation. A Gateway provides an entry point to the root PDOs. A Gateway could be even considered as an anti-Service Façade – in fact its responsibilities are inverted.
  47. blog.adam-bien.com Gateway PDOs are passive artifacts. It is not possible

    to access them directly without an execution context. The next problem is the stateless nature of most Java EE applications... After a method invocation of a transaction boundary (e.g. a Stateless Session Bean) all JPA-entities (PDOs) become detached. The client loses its state.
  48. blog.adam-bien.com Persistent Domain Object Its just a “real object” “Real

    objects” does mean cohesive classes with encapsulated state, related behavior and with inheritance. Just put business logic into the domain objects and use inheritance were appropriate. JPA turns is really flexible in mapping rich domain objects into relational tables. The more complex logic you have to realize, the easier can object oriented persistence be maintained and developed.
  49. blog.adam-bien.com Persistent Domain Object The real issue are if-statements needed

    to differentiate between the entity types. Such checks are needed to realize type-dependent behavior in procedural way. Every introduction of a new subclass, or even change of the existing business logic requires to find, enhance and test the type checks. The computation of shipping costs dependent on weight and the OrderItem type would look like this in procedural world.
  50. blog.adam-bien.com Persistent Domain Object - procedural type checks... int computeShippingCost(Load

    load){ int shippingCosts = 0; int weight = 0; int defaultCost = 0; for (OrderItem orderItem : load.getOrderItems()) { LoadType loadType = orderItem.getLoadType(); weight = orderItem.getWeight(); defaultCost = weight * 5; switch (loadType) { case BULKY: shippingCosts += (defaultCost + 5); break; case LIGHTWEIGHT: shippingCosts += (defaultCost - 1); break; case STANDARD: shippingCosts += (defaultCost); break; default: throw new IllegalStateException("Unknown type: " + loadType); } } return shippingCosts; }
  51. blog.adam-bien.com Type checks - the object oriented way public int

    getShippingCosts() { int shippingCosts = 0; for (OrderItem orderItem : orderItems) { shippingCosts += orderItem.getShippingCost(); } return shippingCosts; }
  52. blog.adam-bien.com Inheritance does the work public class BulkyItem extends OrderItem{

    public BulkyItem(int weight) { super(weight); } @Override public int getShippingCost() { return super.getShippingCost() + 5; } }
  53. blog.adam-bien.com The procedural construction Load load = new Load(); OrderItem

    standard = new OrderItem(); standard.setLoadType(LoadType.STANDARD); standard.setWeight(5); load.getOrderItems().add(standard); OrderItem light = new OrderItem(); light.setLoadType(LoadType.LIGHTWEIGHT); light.setWeight(1); load.getOrderItems().add(light); OrderItem bulky = new OrderItem(); bulky.setLoadType(LoadType.BULKY); bulky.setWeight(1); load.getOrderItems().add(bulky);
  54. blog.adam-bien.com ...and the fluent way Load build = new Load.Builder().

    withStandardItem(5). withLightweightItem(1). withBulkyItem(1). build();
  55. blog.adam-bien.com Persistent Domain Object PDOs are JPA entities with emphasis

    to domain logic and not the technology. PDO resides in a component which is realized as Java- package with domain-specific name e.g. ordermgmt. The PDO resides in a sub-package (layer) with the name domainordermgmt.domain. This makes the automatic verification of the architecture easier. The name of the domain object is derived from the target domain. Getters and setters are not obligatory – they should be only used in justified cases.
  56. blog.adam-bien.com Persistent Domain Object The methods are not only accessors,

    but they model behavior which also changes the state of the domain objects. All methods are named in fluent way. It is not required to use the term “PDO” in the name of the entity – it is redundant. For identification purposes you could use a @PDO annotation.
  57. blog.adam-bien.com Persistent Domain Object (Rethinking) Java EE 5 together with

    JPA introduced inheritance and polymorphic queries to the persistence layer. JPA entities are just annotated Java classes with only insignificant restrictions, so already object oriented approaches and patterns can be applied to persistence layer now.
  58. blog.adam-bien.com Persistent Domain Object (Rethinking) It’s time to rethink the

    way, how complex logic is going to be developed. The persistence layer should consist of self-contained domain objects with clear responsibilities and encapsulated state and behavior. The persistence is just an aspect concern and should not have any impact on design and not in particular on the amount of logic residing in domain objects.
  59. blog.adam-bien.com Persistent Domain Object (Rethinking) Only the remaining, cross-cutting and

    often procedural logic should be implemented in a Service. Actually the Persistent Domain Objects becomes a best practice and the Anemic Domain Model an anti pattern, ...at least in more ambitious projects.
  60. blog.adam-bien.com Java Context and Dependency Injection (JSR-299) JSR-299 provides a

    powerful new set of services to Java EE components. The lifecycle and interactions of stateful components bound to well- defined lifecycle contexts, where the set of contexts is extensible A sophisticated, typesafe dependency injection mechanism, including a facility for choosing between various components that implement the same Java interface at deployment time Integration with the Unified Expression Language (EL), allowing any component to be used directly within a JSF or JSP page The ability to decorate injected components An event notification model A web conversation context in addition to the three standard web contexts defined by the Java Servlets specification An SPI allowing portable extensions to integrate cleanly with the Java EE environment
  61. blog.adam-bien.com Java Context and Dependency Injection (JSR-299) a completely general

    typesafe dependency injection model, contextual lifecycle management for injectable objects, an event notification model, interceptor bindings via user-defined annotations, typesafe decorators, a complete SPI for integration of third-party web or component frameworks, and integration with JSF, servlets and JSP, including a conversation context for JSF
  62. blog.adam-bien.com Java Context and Dependency Injection (JSR-299) Out of the

    box you can inject into just about any kind of thing in the Java EE environment, including servlets, servlet filters, servlet event listeners, JAX-WS web service endpoints and JAX-RS resources. The kinds of objects you can inject include: managed beans (plain Java classes), local EJB session beans, objects obtained from a producer method or producer field, Java EE component environment resources (datasources, connectors, persistence contexts, JMS message destinations, web services, remote EJBs, etc.)
  63. blog.adam-bien.com Java Context and Dependency Injection (JSR-299) There's an SPI

    so that any third-party framework (for example, a web framework like Wicket) can easily ask the 299 implementation to perform injection upon objects managed by the framework.
  64. blog.adam-bien.com Java Context and Dependency Injection (JSR-299) final class Head

    {} final class Person { private Head head; @Initializer Person(Head head) { this.head=head; } }
  65. blog.adam-bien.com Java Context and Dependency Injection (JSR-299) A maintenance release

    of JSR-299 is planned, which will support the JSR-330 bootstrap API. For now, if you want to run JSR-299 in the SE environment, you'll need to use a vendor-specific bootstrap API.
  66. blog.adam-bien.com JSR-299 Especially interesting for stateful Beans and Domain Driven

    Design. In Java EE 6 there are no conversations (aka Map in HttpSession:-)) JSR-299 will allow multiple sub-sessions inside the HttpSession The lifecycle of @Stateful Beans is managed by web- components -> “memory leaks” possible. DI is more powerful, than in EJB 3.1.