Moving to Java EE 6 and CDI and away from the clutter

78
Move Move to to Java EE 6 and CDI... Java EE 6 and CDI... ...and ...and away away from the from the clutter clutter Dan Allen Principal Software Engineer JBoss by Red Hat

description

Java EE 6 standards and technologies, such as JSR 299 - Contexts & Dependency Injection, significantly reduce complexity, increase developer productivity and insure your freedom from vendor lock-in. This Red Hat webinar explains how Java EE 6 can be even simpler than using proprietary legacy frameworks, and take much less time.

Transcript of Moving to Java EE 6 and CDI and away from the clutter

Page 1: Moving to Java EE 6 and CDI and away from the clutter

Move Move toto Java EE 6 and CDI... Java EE 6 and CDI...

...and ...and awayaway from the from the clutterclutter

Dan AllenPrincipal Software EngineerJBoss by Red Hat

Page 2: Moving to Java EE 6 and CDI and away from the clutter

2 Java EE and CDI | Dan Allen

Agenda

● Java EE 6: All platform, no clutter

● Java EE's new wiring: JSR-299

● JSR-299 principles

● CDI programming model tour

● CDI extensions

● Weld

● Seam 3

Page 3: Moving to Java EE 6 and CDI and away from the clutter

3 Java EE and CDI | Dan Allen

Why reevaluate?

Page 4: Moving to Java EE 6 and CDI and away from the clutter

4 Java EE and CDI | Dan Allen

Landscaping or a roof garden?

Framework X

Java EE

Page 5: Moving to Java EE 6 and CDI and away from the clutter

5 Java EE and CDI | Dan Allen

What is Java EE?

● Standard platform comprised ofmanaged components & services

● Business logic as components

1. Less code

2. Higher signal-to-noise ratio

3. Powerful mechanisms for free

4. Portable knowledge

Page 6: Moving to Java EE 6 and CDI and away from the clutter

6 Java EE and CDI | Dan Allen

The Java EE we always wanted

● No-interface EJBs

● Embeddable EJB container

● Simplified packaging● EJBs in a WAR

● POJOs, finally!

● Annotations + partial descriptors● No more XML-hell XML

● Web profile● GTD in Java EE

Java EE 6Java EE 6

Page 7: Moving to Java EE 6 and CDI and away from the clutter

7 Java EE and CDI | Dan Allen

Web profile stack (read as: all you need)

● Persistence● JPA 2.0● JTA 1.1

● Component model● EJB 3.1 (lite)● CDI 1.0● Bean Validation 1.0

● Presentation● JSF 2.0● Servlet 3.0

● JBoss AS extras● JMS 1.1● JAX-RS 1.1CDI 1.0

Page 8: Moving to Java EE 6 and CDI and away from the clutter

8 Java EE and CDI | Dan Allen

Technology terminology

● JSR-299 (CDI)● Contexts & Dependency Injection for the

Java EE Platform● Weld

● JSR-299 Reference Implementation & TCK● Extended CDI support (Servlets, Java SE)● Portable CDI enhancements and utilities

● Seam 3● Portable extensions for Java EE● Portable integrations with non-Java EE technologies

Page 9: Moving to Java EE 6 and CDI and away from the clutter

9 Java EE and CDI | Dan Allen

Stated goal of JSR-299

Web tier(JSF)

Transactional tier(EJB)

Page 10: Moving to Java EE 6 and CDI and away from the clutter

10 Java EE and CDI | Dan Allen

What CDI provides

● Services for Java EE components● Lifecycle management of stateful beans bound to

well-defined contexts (including conversation context)● A type-safe approach to dependency injection● Interaction via an event notification facility● Reduced coupling between interceptors and beans● Decorators, which intercept specific bean instances● Unified EL integration (bean names)

● SPI for developing extensions for the Java EE platform● Java EE architecture flexible, portable, extensible

Page 11: Moving to Java EE 6 and CDI and away from the clutter

11 Java EE and CDI | Dan Allen

What CDI provides

● Services for Java EE components● Lifecycle management of stateful beans bound to

well-defined contexts (including conversation context)● A type-safe approach to dependency injection● Interaction via an event notification facility● Reduced coupling between interceptors and beans● Decorators, which intercept specific bean instances● Unified EL integration (bean names)

● SPI for developing extensions for the Java EE platform● Java EE architecture flexible, portable, extensible

Page 12: Moving to Java EE 6 and CDI and away from the clutter

12 Java EE and CDI | Dan Allen

CDI: The big picture

● Fill in

● Catalyze

● Evolve

Page 13: Moving to Java EE 6 and CDI and away from the clutter

13 Java EE and CDI | Dan Allen

Whoa, why dependency injection?

● Weakest aspect of Java EE 5

● Closed set of injectable resources● @EJB● @PersistenceContext, @PersistenceUnit● @Resource (e.g., DataSource, UserTransaction)

● Name-based injection is fragile

● Lacked rules

Page 14: Moving to Java EE 6 and CDI and away from the clutter

14 Java EE and CDI | Dan Allen

Leverage and extend Java’s type system

@Annotation

Type

<TypeParam>

This information is pretty useful!

Page 15: Moving to Java EE 6 and CDI and away from the clutter

15 Java EE and CDI | Dan Allen

JSR-299 theme

Loose coupling...

...with strong typingstrong typing

@Inject@Observes

@InterceptorBinding

@Qualifier

Event<Order>

@Produces @WishListList<Product> getWishList()

@UserDatabase EntityManager

Page 16: Moving to Java EE 6 and CDI and away from the clutter

16 Java EE and CDI | Dan Allen

Loose coupling

● Decouple server and client● Contract based on well-defined types and “qualifiers”

● Decouple lifecycle of collaborating components● Stateful components interact like services

● Decouple orthogonal concerns (AOP)● Interceptors & decorators

● Decouple message producer from consumer● Events

Page 17: Moving to Java EE 6 and CDI and away from the clutter

17 Java EE and CDI | Dan Allen

StrongStrong typing typing

● Type-based injection● Eliminate reliance on string-based names● Refactor friendly

● Compiler can detect typing errors● No special authoring tools required● Casting mostly eliminated

● Semantic code errors detected at application startup

● Enables strong tooling● Preemptively detect errors● Navigate relationships

Page 18: Moving to Java EE 6 and CDI and away from the clutter

18 Java EE and CDI | Dan Allen

Strong typing = strong tooling

CDI tools available in JBoss Tools 3.2 - http://jboss.org/tools

Page 19: Moving to Java EE 6 and CDI and away from the clutter

19 Java EE and CDI | Dan Allen

Who's bean is it anyway?

● Everyone throwing around this term “bean”● JSF● EJB● Seam● Spring● Guice● Web Beans

● Need a “unified bean definition”

Page 20: Moving to Java EE 6 and CDI and away from the clutter

20 Java EE and CDI | Dan Allen

Managed bean specification

● Common bean definition

● Instances managed by the container

● Common services● Lifecycle callbacks● Resource injections● Interceptors

● Foundation spec

How managed beans evolved: http://www.infoq.com/news/2009/11/weld10

JSF EJB CDI JAX-RS

ManagedBeans

Page 21: Moving to Java EE 6 and CDI and away from the clutter

21 Java EE and CDI | Dan Allen

CDI bean ingredients

● Set of bean types

● Set of qualifiers

● Scope

● Bean EL name (optional)

● Set of interceptor bindings

● Alternative classification

● Bean implementation class

Auto-discovered!

DI contract

Page 22: Moving to Java EE 6 and CDI and away from the clutter

22 Java EE and CDI | Dan Allen

Welcome to CDI, managed bean!

public class Welcome { public String buildPhrase(String city) { return "Welcome to " + city + "!"; } }

Page 23: Moving to Java EE 6 and CDI and away from the clutter

23 Java EE and CDI | Dan Allen

Welcome to CDI, EJB 3.1 session bean!

@Stateless public class Welcome { public String buildPhrase(String city) { return "Welcome to " + city + "!"; } }

Page 24: Moving to Java EE 6 and CDI and away from the clutter

24 Java EE and CDI | Dan Allen

When is a bean recognized?

● Bean archive (WAR) ● Bean archive (JAR)

beans.xml can be empty!

Page 25: Moving to Java EE 6 and CDI and away from the clutter

25 Java EE and CDI | Dan Allen

Injection 101

public class Greeter { @Inject Welcome w;

public void welcome() { System.out.println( w.buildPhrase("New York")); }}

Page 26: Moving to Java EE 6 and CDI and away from the clutter

26 Java EE and CDI | Dan Allen

Where can it be injected?

● Field

● Method parameter● Constructor*● Initializer● Producer● Observer

Page 27: Moving to Java EE 6 and CDI and away from the clutter

27 Java EE and CDI | Dan Allen

What can be injected?

Managed bean

Object returned by producer

EJB session bean (local or remote)

Java EE resource (DataSource, JMS destination, etc)

JTA UserTransaction

Persistence unit or context

Security principle

Bean Validation factory

Web service reference

Additional resources introduced through SPI

Page 28: Moving to Java EE 6 and CDI and away from the clutter

28 Java EE and CDI | Dan Allen

The bean vs “the other implementation”

public class Welcome { public String buildPhrase(String city) { return "Welcome to " + city + "!"; } }

public class TranslatingWelcome extends Welcome {

@Inject GoogleTranslator translator;

public String buildPhrase(String city) { return translator.translate( "Welcome to " + city + "!"); } }

Page 29: Moving to Java EE 6 and CDI and away from the clutter

29 Java EE and CDI | Dan Allen

Quiz: Which implementation gets injected?

public class Greeter { private Welcome welcome; @Inject void init(Welcome welcome) { this.welcome = welcome; }

...}

It's ambiguous!

Page 30: Moving to Java EE 6 and CDI and away from the clutter

30 Java EE and CDI | Dan Allen

Working out an ambiguous resolution

● Qualifier

● Alternative

● Veto (or hide)

Page 31: Moving to Java EE 6 and CDI and away from the clutter

31 Java EE and CDI | Dan Allen

qualifier

n. an annotation used to resolve an APIimplementation variant at an injection point

Page 32: Moving to Java EE 6 and CDI and away from the clutter

32 Java EE and CDI | Dan Allen

Defining a qualifier

@Qualifier@Retention(RUNTIME)@Target({TYPE, METHOD, FIELD, PARAMETER})public @interface Translating {}

@interface = annotation@interface = annotation

Page 33: Moving to Java EE 6 and CDI and away from the clutter

33 Java EE and CDI | Dan Allen

Qualifying an implementation

@Translatingpublic class TranslatingWelcome extends Welcome {

@Inject GoogleTranslator translator;

public String buildPhrase(String city) { return translator.translate( "Welcome to " + city + "!"); } }

● Qualifiers:● makes type more specific● assign semantic meaning

Page 34: Moving to Java EE 6 and CDI and away from the clutter

34 Java EE and CDI | Dan Allen

Qualifier as a “binding type”

Page 35: Moving to Java EE 6 and CDI and away from the clutter

35 Java EE and CDI | Dan Allen

Explicitly request qualified interface

public class Greeter {

private Welcome welcome;

@Inject void init(@Translating Welcome welcome) { this.welcome = welcome; }

public void welcomeVisitors() { System.out.println( welcome.buildPhrase("New York")); }}

No reference to implementation class!No reference to implementation class!

Page 36: Moving to Java EE 6 and CDI and away from the clutter

36 Java EE and CDI | Dan Allen

Alternative bean

● Swap replacement implementation per deployment

● Replaces bean and its producers

● Activated in /META-INF/beans.xml● Disabled by default

In order words, a replacement

Page 37: Moving to Java EE 6 and CDI and away from the clutter

37 Java EE and CDI | Dan Allen

Defining an alternative

@Alternativepublic class TranslatingWelcome extends Welcome {

@Inject GoogleTranslator translator;

public String buildPhrase(String city) { return translator.translate( "Welcome to " + city + "!"); }}

Page 38: Moving to Java EE 6 and CDI and away from the clutter

38 Java EE and CDI | Dan Allen

Substituting the alternative using beans.xml

<beans> <alternatives> <class>com.acme.TranslatingWelcome</class> </alternatives></beans>

Page 39: Moving to Java EE 6 and CDI and away from the clutter

39 Java EE and CDI | Dan Allen

Assigning a bean (EL) name

@Named("greeter")public class Greeter { private Welcome welcome;

@Inject void init(Welcome welcome) { this.welcome = welcome; }

public void welcomeVisitors() { System.out.println( welcome.buildPhrase("New York")); }}

Page 40: Moving to Java EE 6 and CDI and away from the clutter

40 Java EE and CDI | Dan Allen

Assigning a bean (EL) name by convention

@Namedpublic class Greeter { private Welcome welcome;

@Inject void init(Welcome welcome) { this.welcome = welcome; }

public void welcomeVisitors() { System.out.println( welcome.buildPhrase("New York")); }}

Bean name is decapitalizedsimple class name Bean name is decapitalizedsimple class name

Page 41: Moving to Java EE 6 and CDI and away from the clutter

41 Java EE and CDI | Dan Allen

Welcome to CDI, JSF!

● Use the bean directly in the JSF view<h:form> <h:commandButton value="Welcome visitors" action="#{greeter.welcomeVisitors}"/></h:form>

Page 42: Moving to Java EE 6 and CDI and away from the clutter

42 Java EE and CDI | Dan Allen

CDI

JSFmanaged

beans

Page 43: Moving to Java EE 6 and CDI and away from the clutter

43 Java EE and CDI | Dan Allen

Stashing the bean in a context

@Named@RequestScopedpublic class Greeter { @Inject private Welcome w; private String city;

public String getCity() { return city; }

public void setCity(String city) { this.city = city; }

public void welcomeVisitors() { System.out.println(w.buildPhrase(city)); }}

Bean stored for duration of requestBean stored for duration of request

Page 44: Moving to Java EE 6 and CDI and away from the clutter

44 Java EE and CDI | Dan Allen

Collapsing layers with state management

● Now it’s possible for bean to hold state<h:form> <h:inputText value="#{greeter.city}"/> <h:commandButton value="Welcome visitors" action="#{greeter.welcomeVisitors}"/></h:form>

Prints:Welcome to New York!

New York

Page 45: Moving to Java EE 6 and CDI and away from the clutter

45 Java EE and CDI | Dan Allen

Mission accomplished: We have a deal!

Web tier(JSF)

Business tier(managed bean)

Page 46: Moving to Java EE 6 and CDI and away from the clutter

46 Java EE and CDI | Dan Allen

Scope types and contexts

● @Dependent – Default scope● Bound to lifecycle of bean holding reference

● @ApplicationScoped

● @RequestScoped

● @SessionScoped

● @ConversationScoped – JSF scope● Request ≤ Conversation Session≪

● Custom scopes● Define scope type annotation (e.g., @FlashScoped)● Implement the context API in an extension

Servlet scopes

Page 47: Moving to Java EE 6 and CDI and away from the clutter

47 Java EE and CDI | Dan Allen

Scope transparency

● Scopes not visible to client (no coupling)

● Scoped beans are proxied for thread safety

Page 48: Moving to Java EE 6 and CDI and away from the clutter

48 Java EE and CDI | Dan Allen

producer method

n. a method whose return value producesan injectable object

Page 49: Moving to Java EE 6 and CDI and away from the clutter

49 Java EE and CDI | Dan Allen

Producer method examples

@Produces @RequestScopedpublic FacesContext getFacesContext() { return FacesContext.getInstance();}

@Producespublic PaymentProcessor getPaymentProcessor( @Synchronous PaymentProcessor sync, @Asynchronous PaymentProcessor async) { return isSynchronous() ? sync : async;}

@Produces @SessionScoped @WishListpublic List<Product> getWishList() { return em.createQuery("...").getResultList();}

From non-beanFrom non-bean

Runtime selectionRuntime selection

Dynamic result setDynamic result set

Page 50: Moving to Java EE 6 and CDI and away from the clutter

50 Java EE and CDI | Dan Allen

Injecting producer return values

@Inject FacesContext ctx;

@Inject PaymentProcessor pp;

@Inject @WishList List<Product> wishlist;

Origin of product is hidden at injection point

Page 51: Moving to Java EE 6 and CDI and away from the clutter

51 Java EE and CDI | Dan Allen

Bridging Java EE resources to CDI

public class UserEntityManagerProducer { @Produces @InventoryRepository @PersistenceContext(unitName = "inventory") private EntityManager inventory;}

public class PricesTopicProducer { @Produces @Prices @Resource(name = "java:global/env/jms/Prices") private Topic pricesTopic;}

Producer fields can promoteJava EE resources as beansProducer fields can promoteJava EE resources as beans

Page 52: Moving to Java EE 6 and CDI and away from the clutter

52 Java EE and CDI | Dan Allen

Injecting resources in type-safe way

public class UserManager { @Inject @InventoryRepository EntityManager inventory; ...}

public class StockDisplay { @Inject @Prices Topic pricesTopic; ...}

Eliminates string-basednames at injection pointsEliminates string-basednames at injection points

Page 53: Moving to Java EE 6 and CDI and away from the clutter

53 Java EE and CDI | Dan Allen

Java EE 6: Simple, clean and integrated

@Stateless@Path("/product")public class ProductResourceHandler { @Inject @InventoryDatabase EntityManager em;

@GET @Path("/{id:[1-9][0-9]+}") @Produces("application/xml") public Product getProduct(@PathParam("id") Long id) { return em.find(Product.class, id); }}

Page 54: Moving to Java EE 6 and CDI and away from the clutter

54 Java EE and CDI | Dan Allen

Rethinking interceptors

@Interceptors( SecurityInterceptor.class, TransactionInterceptor.class, LoggingInterceptor.class)@Stateful public class BusinessComponent { ...}

Um, what's the point?

Page 55: Moving to Java EE 6 and CDI and away from the clutter

55 Java EE and CDI | Dan Allen

Define an interceptor binding type

@InterceptorBinding@Retention(RUNTIME)@Target({TYPE, METHOD})public @interface Secure {}

Page 56: Moving to Java EE 6 and CDI and away from the clutter

56 Java EE and CDI | Dan Allen

Mark the interceptor implementation

@Secure@Interceptorpublic class SecurityInterceptor {

@AroundInvoke public Object aroundInvoke(InvocationContext ctx) throws Exception { // enforce security... ctx.proceed(); }

}

Page 57: Moving to Java EE 6 and CDI and away from the clutter

57 Java EE and CDI | Dan Allen

Interceptor wiring with proper semantics

@Securepublic class AccountManager {

public boolean transfer(Account a, Account b) { ... }

}

Page 58: Moving to Java EE 6 and CDI and away from the clutter

58 Java EE and CDI | Dan Allen

Enabling interceptors using beans.xml

<beans> <interceptors> <class>com.acme.SecurityInterceptor</class> <class>com.acme.TransactionInterceptor</class> </interceptors></beans>

Interceptors applied in order listedInterceptors applied in order listed

Page 59: Moving to Java EE 6 and CDI and away from the clutter

59 Java EE and CDI | Dan Allen

Annotation jam!

@Secure@Transactional@RequestScoped@Namedpublic class AccountManager {

public boolean transfer(Account a, Account b) { ... }

}

Page 60: Moving to Java EE 6 and CDI and away from the clutter

60 Java EE and CDI | Dan Allen

stereotype

n. an annotation used to group commonarchitectural patterns (recurring roles)

Page 61: Moving to Java EE 6 and CDI and away from the clutter

61 Java EE and CDI | Dan Allen

Define a stereotype to bundle annotations

@Secure@Transactional@RequestScoped@Named@Stereotype@Retention(RUNTIME)@Target(TYPE)public @interface BusinessComponent {}

Page 62: Moving to Java EE 6 and CDI and away from the clutter

62 Java EE and CDI | Dan Allen

Using a stereotype

@BusinessComponentpublic class AccountManager {

public boolean transfer(Account a, Account b) { ... }

}

Page 63: Moving to Java EE 6 and CDI and away from the clutter

63 Java EE and CDI | Dan Allen

Portable extensions

● Auto-discovered

● Integrate with the container by:● Providing beans, interceptors or decorators● Injecting dependencies into its own objects● Contributing a scope and context implementation● Augmenting or overriding annotation metadata

● Observe container lifecycle events● Before/after bean discovery● After deployment validation● Processing bean, producer, observer, or injection target

Service Provider Interface (SPI)

Page 64: Moving to Java EE 6 and CDI and away from the clutter

64 Java EE and CDI | Dan Allen

Page 65: Moving to Java EE 6 and CDI and away from the clutter

65 Java EE and CDI | Dan Allen

Weld: The axis of CDI

Implement(RI)

Improve(Extensions)

Validate(TCK)

Reach(Servlet, SE)

Page 66: Moving to Java EE 6 and CDI and away from the clutter

66 Java EE and CDI | Dan Allen

JSR-299 RI & TCK

● Reference Implementation (RI)

● Technology Compatibility Kit (TCK)

● Developer-oriented reference guide

Other implementations:● Apache OpenWebBeans● Resin CanDI

Other implementations:● Apache OpenWebBeans● Resin CanDI

Page 67: Moving to Java EE 6 and CDI and away from the clutter

67 Java EE and CDI | Dan Allen

Weld “X”

● A library of Generally Useful Stuff™

● Enhancements to CDI programming model● Bean discovery control● Injectable logger and resource loader● EL evaluator and more...

● Utilities for framework & extension writers● Annotation metadata utilties● JavaBean inspectors● BeanManager locator and more...

Page 68: Moving to Java EE 6 and CDI and away from the clutter

68 Java EE and CDI | Dan Allen

Page 69: Moving to Java EE 6 and CDI and away from the clutter

69 Java EE and CDI | Dan Allen

Seam’s mission statement

To provide a fully integrated development

platform for building rich Internet applicationsbased upon the Java EE environment.

Page 70: Moving to Java EE 6 and CDI and away from the clutter

70 Java EE and CDI | Dan Allen

Seam’s new modular ecosystem

Page 71: Moving to Java EE 6 and CDI and away from the clutter

71 Java EE and CDI | Dan Allen

Portable modules

● Module per domain or integration

● Independently...● lead● versioned● released

● Per-module structure● Based on CDI● API & implementation● Reference documentation & examples

Page 72: Moving to Java EE 6 and CDI and away from the clutter

72 Java EE and CDI | Dan Allen

Stack releases

Page 73: Moving to Java EE 6 and CDI and away from the clutter

73 Java EE and CDI | Dan Allen

What's on the menu so far?

● Drools

● jBPM

● JMS

● Faces

● International

● Persistence

● JavaScript remoting

● Security

● Servlet

● Wicket

● XML configuration

● Exception handling

...and more http://github.com/seam

Page 74: Moving to Java EE 6 and CDI and away from the clutter

74 Java EE and CDI | Dan Allen

XML-based configuration

<beans ... xmlns:app="java:urn:com.acme"> <app:TranslatingWelcome> <app:Translating/> <app:defaultLocale>en-US</app:defaultLocale> </app:TranslatingWelcome></beans>

● Define, specialize or override beans

● Add annotations (qualifiers, interceptor bindings, ...)

● Assign initial property values

Page 75: Moving to Java EE 6 and CDI and away from the clutter

75 Java EE and CDI | Dan Allen

Arquillian: Container-oriented testing for Java EE

@RunWith(Arquillian.class)public class GreeterTestCase {

@Deployment public static Archive<?> createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClasses(Greeter.class, GreeterBean.class); } @EJB private Greeter greeter; @Test public void shouldBeAbleToInvokeEJB() throws Exception { assertEquals("Hello, Earthlings", greeter.greet("Earthlings")); }} http://jboss.org/arquillian

Page 76: Moving to Java EE 6 and CDI and away from the clutter

76 Java EE and CDI | Dan Allen

Summary

● Java EE 6 is leaner and more productive

● JSR-299 (CDI) provides a set of services for Java EE● Bridges JSF and EJB● Offers loose coupling with strong typingstrong typing● Provides a type-based event bus● Catalyzed change in Java EE 6● Introduced SPI for third-party integration with Java EE

● Weld: JSR-299 reference implementation & add-ons

● Seam 3: Portable extensions for Java EE

Page 77: Moving to Java EE 6 and CDI and away from the clutter

77 Java EE and CDI | Dan Allen

How do I get started?

● Download a Java EE 6 container● JBoss AS 6

http://jboss.org/jbossas

● Generate a Java EE project using a Maven archetype● http://tinyurl.com/goweld

● Read the Weld reference guide● http://tinyurl.com/weld-reference-101

● Browse the CDI API docs● http://docs.jboss.org/cdi/api/latest/

● Check out the Seam 3 project● http://seamframework.org/Seam3

● GlassFish V3http://glassfish.org

Page 78: Moving to Java EE 6 and CDI and away from the clutter

Say goodbye to the Say goodbye to the clutterclutter !!

Dan AllenPrincipal Software EngineerJBoss by Red Hat

http://seamframework.org/Weldhttp://seamframework.org/Seam3