SlideShare a Scribd company logo
1 of 263
Download to read offline
Apache Wicket

and Java EE sitting in a tree
Martijn Dashorst

topicus onderwijs
APACHE WICKET
Wicket and Java EE
servlet 3
JSF 2
EJB 3.1
JPA 2
JSP
CDI
JTA
Bean
Validation
JAX-WS
JAX-RPC
JAXR
SAAJ
JAX-RS
JAXB
JMS
JAAS
JASPIC
JACC
JCA
Java Mail
JSR 88
JSR 77
RMI
JNDI
Java EE
web profile
s/[JSF|JSP]/Wicket/🌍
Wicket's mission statement from 2004
servlet 3
JSF 2
EJB 3.1
JPA 2
JSP
CDI
JTA
Bean
Validation
JAX-WS
JAX-RPC
JAXR
SAAJ
JAX-RS
JAXB
JMS
JAAS
JASPIC
JACC
JCA
Java Mail
JSR 88
JSR 77
RMI
JNDI
Java EE
web profile
servlet 3
JSF 2
EJB 3.1
JPA 2
JSP
CDI
JTA
Bean
Validation
JAX-WS
JAX-RPC
JAXR
SAAJ
JAX-RS
JAXB
JMS
JAAS
JASPIC
JACC
JCA
Java Mail
JSR 88
JSR 77
RMI
JNDI
Java EE
web profile
Arquillian
What is Wicket?
wicket |ˈwɪkɪt|
noun
1 Cricket each of the sets of three stumps with two bails across the top at either end of the pitch,
defended by a batsman.
• the prepared strip of ground between two sets of stumps. when they inspected the wicket, they found it being
rolled by some prisoners.
• the dismissal of a batsman; each of ten dismissals regarded as marking a division of a side's innings:
Darlington won by four wickets.
2 (also wicket door or wicket gate)a small door or gate, especially one beside or in a larger one.
• N. Amer. an opening in a door or wall, often fitted with glass or a grille and used for selling tickets or a similar
purpose.
3 N. Amer. a croquet hoop.
PHRASES
at the wicket Cricket 1 batting: the batsman remained at the wicket. 2 by the wicketkeeper: he was caught at
the wicket chasing a wide one.
keep wicket Cricket be a wicketkeeper.
lose a wicket Cricket (of the batting side) have a batsman dismissed. the tourists lost their last seven wickets for
94.
a sticky wicket Cricket a pitch that has been drying after rain and is difficult to bat on. • informal a tricky
or awkward situation: I might be on a sticky wicket if I used that line.
over the wicket Cricket (referring to which side of the wicket a bowler runs when bowling) to the left of
the wicket if a right-handed bowler and the right of the wicket if a left-handed bowler.
round the wicket Cricket (referring to which side of the wicket a bowler runs when bowling) to the right
of the wicket if a right-handed bowler and the left of the wicket if a left-handed bowler.
take a wicket Cricket (of a bowler or a fielding side) dismiss a batsman.
ORIGIN Middle English (in the sense ‘small door or grille’): from Anglo-Norman French and Old
Northern French wiket; origin uncertain, usually referred to the Germanic root of Old Norse vīkja ‘to
turn, move’. Cricket senses date from the late 17th cent.
wicket |ˈwɪkɪt|
noun
1 a component oriented, open source, Java
web application framework
components everywhere
components everywhere
components everywhere
Injection (EJB, CDI)
Conversations (CDI)
JPA
Bean validation
Arquillian
Cheese Store
Example
1. Setup project
2. Add 'domain layer'
3. Add components
First steps
1. setup the project
Remove unnecessary files
Rename package to
'com.cheesr.web'
package com.cheesr.web;
import org.apache.wicket.markup.html.WebPage;
public class Index extends WebPage {
public Index() {
}
}
package com.cheesr.web;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.WebApplica
public class WicketApplication extends WebApplica
@Override
public Class<? extends WebPage> getHomePage() {
return Index.class;
}
@Override
public void init() {
super.init();
}
}
2. Add 'domain model'
entities
package com.cheesr.dao;
public class CheeseDao {
}
package com.cheesr.dao;
public class CheeseDao {
public List<Cheese> getCheeses() {
}
}
package com.cheesr.dao;
/*...*/
public class CheeseDao {
public List<Cheese> getCheeses() {
return asList();
}
}
package com.cheesr.dao;
/*...*/
public class CheeseDao {
public List<Cheese> getCheeses() {
return asList(
new Cheese());
}
}
package com.cheesr.dao;
/*...*/
public class CheeseDao {
public List<Cheese> getCheeses() {
return asList(
new Cheese(
"Gouda",
"Named after the Dutch town of Gouda, j",
1.99));
}
}
package com.cheesr.dao;
/*...*/
public class CheeseDao {
public List<Cheese> getCheeses() {
return asList(
new Cheese(
"Gouda",
"Named after the Dutch town of Gouda, j",
1.99),
new Cheese(
"Edam",
"This is a pressed, semi-hard to hard c",
2.99));
}
}
package com.cheesr.dao;
/*...*/
public class CheeseDao {
public List<Cheese> getCheeses() {
return asList(
new Cheese(
"Gouda",
"Named after the Dutch town of Gouda, j",
1.99),
new Cheese(
"Edam",
"This is a pressed, semi-hard to hard c",
2.99),
new Cheese(
"Camembert",
"A very famous French cheese, Camembert",
3.99));
}
}
package com.cheesr.dao;
public class OrderDao {
}
package com.cheesr.dao;
public class OrderDao {
public void save(Order order) {
}
}
package com.cheesr.dao;
public class OrderDao {
private List<Order> orders = new ArrayList<>();
public void save(Order order) {
}
}
package com.cheesr.dao;
public class OrderDao {
private List<Order> orders = new ArrayList<>();
public void save(Order order) {
orders.add(order);
}
}
package com.cheesr.dao;
public class OrderDao {
private List<Order> orders = new ArrayList<>();
public void save(Order order) {
orders.add(order);
}
public List<Order> list() {
}
}
package com.cheesr.dao;
public class OrderDao {
private List<Order> orders = new ArrayList<>();
public void save(Order order) {
orders.add(order);
}
public List<Order> list() {
return Collections.unmodifiableList(orders);
}
}
3. Add components
<div class="cheese">
<h3>Gouda</h3>
<p>Named after the Dutch town of Gouda, just ou
<p>
<span>$1.99</span>
<a href="#">Add to cart</a>
</p>
</div>
<div wicket:id="cheese" class="cheese">
<h3 wicket:id="name">Gouda</h3>
<p wicket:id="description">Named after the Dutc
<p>
€<span wicket:id="price">1.99</span>
<a href="#">Add to cart</a>
</p>
</div>
public class Index extends WebPage {
public Index() {
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {
});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
}
});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("description", c.getDescriptio
item.add(new Label("price", c.getPrice()));
}
});
}
}
<h3>Your Selection</h3>
<table>
<tbody>
<tr>
<td>Gouda</td>
<td>€<span>1.99</span></td>
<td><a href="#">remove</a></td>
</tr>
</tbody>
<tfoot>
<tr class="total">
<th>Total</th>
<td>$1.99</td>
<td>&nbsp;</td>
</tr>
</tfoot>
</table>
<h3>Your Selection</h3>
<table>
<tbody>
<tr wicket:id="item">
<td wicket:id="name">Gouda</td>
<td>€<span wicket:id="price">1.99</span></td>
<td><a href="#">remove</a></td>
</tr>
</tbody>
<tfoot>
<tr class="total">
<th>Total</th>
<td>$1.99</td>
<td>&nbsp;</td>
</tr>
</tfoot>
</table>
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {
});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {
@Override
protected void populateItem(ListItem<Cheese> item) {
}
});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
}
});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("price", c.getPrice()));
}
});
}
}
<div wicket:id="cheese" class="cheese">
<h3 wicket:id="name">Gouda</h3>
<p wicket:id="description">Named after the Dutc
<p>
€<span wicket:id="price">1.99</span>
<a href="#">Add to cart</a>
</p>
</div>
<div wicket:id="cheese" class="cheese">
<h3 wicket:id="name">Gouda</h3>
<p wicket:id="description">Named after the Dutc
<p>
€<span wicket:id="price">1.99</span>
<a wicket:id="price" href="#">Add to cart</a>
</p>
</div>
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("description", c.getDescription()))
item.add(new Label("price", c.getPrice()));
}
});
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("description", c.getDescription()))
item.add(new Label("price", c.getPrice()));
item.add(new Link<Cheese>("price", item.getModel()));
}
});
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("description", c.getDescription()))
item.add(new Label("price", c.getPrice()));
item.add(new Link<Cheese>("price", item.getModel()) {
});
}
});
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("description", c.getDescription()))
item.add(new Label("price", c.getPrice()));
item.add(new Link<Cheese>("price", item.getModel()) {
@Override
public void onClick() {
}
});
}
});
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("description", c.getDescription()))
item.add(new Label("price", c.getPrice()));
item.add(new Link<Cheese>("price", item.getModel()) {
@Override
public void onClick() {
Cheese cheese = getModelObject();
}
});
}
});
add(new ListView<Cheese>("cheese", cheeses) {
@Override
protected void populateItem(ListItem<Cheese> item) {
Cheese c = item.getModelObject();
item.add(new Label("name", c.getName()));
item.add(new Label("description", c.getDescription()))
item.add(new Label("price", c.getPrice()));
item.add(new Link<Cheese>("price", item.getModel()) {
@Override
public void onClick() {
Cheese cheese = getModelObject();
cart.getItems().add(cheese);
}
});
}
});
Injection (EJB, CDI)
Conversations (CDI)
JPA
Bean validation
Testing with Arquillian
Using EJBs
Add EJB dependencies 

to project
Make DAOs EJBs
Inject DAOs
Steps
<dependencies>
<!-- EJB DEPENDENCIES -->
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
<scope>provided</scope>
</dependency>
…
</dependencies>
Add EJB dependencies 

to project
Make DAOs EJBs
Inject DAOs
Steps
public class CheeseDao {
public List<Cheese> getCheeses() {…}
}
public class OrderDao {
public void save(Order order) {…}
public List<Order> list() {…}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {…}
}
public class CheeseDao {
public List<Cheese> getCheeses() {…}
}
public class OrderDao {
public void save(Order order) {…}
public List<Order> list() {…}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {…}
}
@Stateless
public class CheeseDao {
public List<Cheese> getCheeses() {…}
}
public class OrderDao {
public void save(Order order) {…}
public List<Order> list() {…}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {…}
}
@Stateless
public class CheeseDao {
public List<Cheese> getCheeses() {…}
}
@Stateless
public class OrderDao {
public void save(Order order) {…}
public List<Order> list() {…}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
public Index() {…}
}
@Stateless
public class CheeseDao {
public List<Cheese> getCheeses() {…}
}
@Stateless
public class OrderDao {
public void save(Order order) {…}
public List<Order> list() {…}
}
public class Index extends WebPage {
private CheeseDao cheeseDao;
public Index() {…}
}
Add EJB dependencies 

to project
Make DAOs EJBs
Inject DAOs
Steps
@Stateless
public class CheeseDao {
public List<Cheese> getCheeses() {…}
}
@Stateless
public class OrderDao {
public void save(Order order) {…}
public List<Order> list() {…}
}
public class Index extends WebPage {
@EJB
private CheeseDao cheeseDao;
public Index() {…}
}
21:20:55,305 Processing weld deployment cheesr.war
21:20:55,313 JNDI bindings for session bean named CheeseDao
in deployment unit deployment "cheesr.war" are as follows:
java:global/cheesr/CheeseDao!com.cheesr.dao.CheeseDao
java:app/cheesr/CheeseDao!com.cheesr.dao.CheeseDao
java:module/CheeseDao!com.cheesr.dao.CheeseDao
java:global/cheesr/CheeseDao
java:app/cheesr/CheeseDao
java:module/CheeseDao
21:20:55,335 Starting Services for CDI deployment:
cheesr.war
21:20:55,340 Starting weld service for deployment
cheesr.war
public class Index extends WebPage
{
@EJB
private CheeseDao cheeseDao;
private Cart cart = new Cart();
public Index()
{
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
}
}
public class Index extends WebPage
{
@EJB
private CheeseDao cheeseDao;
private Cart cart = new Cart();
public Index()
{
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
}
}
Wicket is unmanaged, container doesn't
know about Pages, Components, etc.
<dependencies>
<!-- EJB DEPENDENCIES -->
<dependency>
<groupId>org.jboss.spec.javax.ejb</groupId>
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wicketstuff</groupId>
<artifactId>wicketstuff-javaee-inject</artifactId>
<version>6.17.0</version>
</dependency>
</dependencies>
public class WicketApplication extends WebApplication
{
@Override
public Class< ? extends WebPage> getHomePage()
{
return Index.class;
}
@Override
public void init()
{
super.init();
}
}
public class WicketApplication extends WebApplication
{
@Override
public Class< ? extends WebPage> getHomePage()
{
return Index.class;
}
@Override
public void init()
{
super.init();
getComponentInstantiationListeners()
.add(new JavaEEComponentInjector(this));
}
}
• add EJB dependency and wicketstuff-
javaee-inject dependency
• make DAOs EJBs
• configure component instantiation listener
• now you can use @EJB injection
Using CDI for injection
<dependencies>
<!-- CDI DEPENDENCIES -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-cdi-1.1</artifactId>
<version>6.18.0</version>
</dependency>
</dependencies>
public class WicketApplication extends WebApplication
{
@Override
public void init()
{
super.init();
}
}
public class WicketApplication extends WebApplication
{
@Override
public void init()
{
super.init();
CdiConfiguration cdiConfiguration =
new CdiConfiguration();
cdiConfiguration.configure(this);
}
}
@ApplicationScoped
public class MessageOfTheDay
{
public String getMessage()
{
return "What happens to the hole when the cheese is go
}
}
public class Index extends WebPage {
@EJB
private CheeseDao cheeseDao;
public Index()
{
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
}
}
public class Index extends WebPage {
@EJB
private CheeseDao cheeseDao;
@Inject
private MessageOfTheDay message;
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
}
}
public class Index extends WebPage {
@EJB
private CheeseDao cheeseDao;
@Inject
private MessageOfTheDay message;
public Index() {
add(new Label("message", message.getMessage()));
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
}
}
Injecting in non-managed
objects
public class MessageModel
extends LoadableDetachableModel<String> {
@Inject
private MessageOfTheDay messages;
@Override
protected String load() {
return messages.getMessage();
}
}
Caused by: java.lang.NullPointerException
at com.cheesr.web.MessageModel.load(MessageModel.java:15) [:]
at com.cheesr.web.MessageModel.load(MessageModel.java:1) [:]
at org.apache.wicket.model.LoadableDetachableModel.getObject(
at org.apache.wicket.Component.getDefaultModelObject(Componen
... 55 more
public class MessageModel
extends LoadableDetachableModel<String> {
@Inject
private MessageOfTheDay messages;
@Override
protected String load() {
return messages.getMessage();
}
}
public class MessageModel
extends LoadableDetachableModel<String> {
@Inject
private MessageOfTheDay messages;
public MessageModel() {
NonContextual.of(MessageModel.class).inject(this);
}
@Override
protected String load() {
return messages.getMessage();
}
}
• Add wicket-cdi-1.1 and javax.cdi-api
• Configure Wicket's CdiConfiguration
• Use @Inject injection
• Use NonContextual in non-managed
objects
Injection (EJB, CDI)
Conversations (CDI)
JPA
Bean validation
Testing with Arquillian
4. Navigate to Checkout
5. Implement Checkout
6. Make Cart Conversation Scoped
Next steps
4. navigate to checkout
<div id="cart">
<h3>Your Selection</h3>
<table>
<tbody>…</tbody>
<tfoot>…</tfoot>
</table>
<input type="button" value="Check out" />
</div>
<div id="cart">
<h3>Your Selection</h3>
<table>
<tbody>…</tbody>
<tfoot>…</tfoot>
</table>
<input wicket:id="checkout" type="button" value="Check ou
</div>
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
add(new Link<Void>("checkout") {});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
add(new Link<Void>("checkout") {
@Override
public void onClick() {
}
});
}
}
public class Index extends WebPage {
private CheeseDao cheeseDao = new CheeseDao();
private Cart cart = new Cart();
public Index() {
List<Cheese> cheeses = cheeseDao.getCheeses();
add(new ListView<Cheese>("cheese", cheeses) {…});
add(new ListView<Cheese>("item", cart.getItems()) {…})
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class CheckoutPage extends WebPage {
private Cart cart = new Cart();
public CheckoutPage(Cart cart) {
this.cart = cart;
}
}
5. implement checkout
<form >
<h3>Check out</h3>
<p>Please enter your billing address.</p>
<table>
<tr>
<th>Name</th>
<td><input type="text" /></td>
</tr>
<tr>
<th>Street</th>
<td><input type="text" /></td>
</tr>
<tr>
<th>Zipcode</th>
<td><input type="text" /></td>
</tr>
<tr>
<th>City</th>
<td><input type="text" /></td>
</tr>
<form wicket:id="form">
<h3>Check out</h3>
<p>Please enter your billing address.</p>
<table>
<tr>
<th>Name</th>
<td><input type="text" /></td>
</tr>
<tr>
<th>Street</th>
<td><input type="text" /></td>
</tr>
<tr>
<th>Zipcode</th>
<td><input type="text" /></td>
</tr>
<tr>
<th>City</th>
<td><input type="text" /></td>
</tr>
public class CheckoutPage extends WebPage {
private Cart cart;
public CheckoutPage(Cart cart) {
this.cart = cart;
}
}
public class CheckoutPage extends WebPage {
private Cart cart;
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {};
add(form);
}
}
public class CheckoutPage extends WebPage {
private Cart cart;
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
private Cart cart;
private Order order = new Order();
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
private Cart cart;
private Order order = new Order();
@EJB
private OrderDao orders;
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {
}
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {
OrderItem item = new OrderItem();
item.setOrder(order);
item.setCheese(cheese);
order.getItems().add(item);
}
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {
OrderItem item = new OrderItem();
item.setOrder(order);
item.setCheese(cheese);
order.getItems().add(item);
}
orders.save(order);
}
};
add(form);
}
}
6. make Cart 

Conversation Scoped
What does the navigation between
shopping and checkout look like?
public class Index extends WebPage {
public Index() {
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class CheckoutPage extends WebPage {
private Cart cart;
public CheckoutPage(Cart cart) {
this.cart = cart;
…
}
}
public class Index extends WebPage {
public Index() {
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class CheckoutPage extends WebPage {
private Cart cart;
public CheckoutPage(Cart cart) {
this.cart = cart;
…
}
}
public class Index extends WebPage {
public Index() {
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class CheckoutPage extends WebPage {
private Cart cart;
public CheckoutPage(Cart cart) {
this.cart = cart;
…
}
}
Cart should be

conversation scoped
public class Cart implements Serializable {
public Cart() {
}
public void setItems(List<Cheese> items) {
this.items = items;
}
public List<Cheese> getItems() {
return items;
}
public double getTotal() {
return items.stream().mapToDouble(Cheese::getPrice).su
}
}
@ConversationScoped
public class Cart implements Serializable {
private List<Cheese> items = new ArrayList<>();
public Cart() {
}
public void setItems(List<Cheese> items) {
this.items = items;
}
public List<Cheese> getItems() {
return items;
}
public double getTotal() {
return items.stream().mapToDouble(Cheese::getPrice).su
}
}
Let's get this conversation started

public class Index extends WebPage {
…
public Index() {
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class Index extends WebPage {
…
@Inject
private Conversation shopping;
public Index() {
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class Index extends WebPage {
…
@Inject
private Conversation shopping;
public Index() {
…
shopping.begin();
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class Index extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart = new Cart();
public Index() {
…
shopping.begin();
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class Index extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public Index() {
…
shopping.begin();
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage(cart));
}
});
}
}
public class Index extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public Index() {
…
shopping.begin();
…
add(new Link<Void>("checkout") {
@Override
public void onClick() {
setResponsePage(new CheckoutPage());
}
});
}
}
public class CheckoutPage extends WebPage {
@EJB
private OrderDao orders;
private Order order = new Order();
private Cart cart;
public CheckoutPage(Cart cart) {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {…};
add(form);
}
}
public class CheckoutPage extends WebPage {
@EJB
private OrderDao orders;
private Order order = new Order();
private Cart cart;
public CheckoutPage() {
this.cart = cart;
Form<Void> form = new Form<Void>("form") {…};
add(form);
}
}
public class CheckoutPage extends WebPage {
@EJB
private OrderDao orders;
private Order order = new Order();
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {…};
add(form);
}
}
public class CheckoutPage extends WebPage {
@EJB
private OrderDao orders;
private Order order = new Order();
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {…};
add(form);
}
}
Let's end this conversation

public class CheckoutPage extends WebPage {
…
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {…};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {…}
orders.save(order);
}
};
add(form);
}
}
end conversation
here...
public class CheckoutPage extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {}
orders.save(order);
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {}
orders.save(order);
shopping.end();
}
};
add(form);
}
}
localhost:8080/cheesr/?0&cid=1
⟳
public class CheckoutPage extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {}
orders.save(order);
shopping.end();
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {}
orders.save(order);
shopping.end();
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {}
orders.save(order);
shopping.end();
}
};
add(form);
}
}
public class CheckoutPage extends WebPage {
…
@Inject
private Conversation shopping;
@Inject
private Cart cart;
public CheckoutPage() {
Form<Void> form = new Form<Void>("form") {
@Override
protected void onSubmit() {
for (Cheese cheese : cart.getItems()) {}
orders.save(order);
shopping.end();
setResponsePage(Index.class);
}
};
add(form);
}
• Add wicket-cdi-1.1 and javax.cdi-api
• Configure Wicket's CdiConfiguration
• Use @Inject injection and
@ConversationScoped
• Use NonContextual in non-managed
objects
Injection (EJB, CDI)
Conversations (CDI)
JPA
Bean validation
Testing with Arquillian
Cheese, Order, OrderItem now @Entity
Order → OrderItem

@OneToMany(fetchType=LAZY)
OrderItem → Cheese, OrderItem → Order

@ManyToOne(optional=false)
CheeseDao, OrderDao now

@Stateless

@TransactionAttribute(REQUIRED)
A refreshing model
A model that reloads data from DB 

for every render
public class OrdersModel {

}
public class OrdersModel 

extends LoadableDetachableModel<List<Order>> {
}
public class OrdersModel 

extends LoadableDetachableModel<List<Order>> {
@Override
protected List<Order> load() {
}
}
public class OrdersModel 

extends LoadableDetachableModel<List<Order>> {
@Override
protected List<Order> load() {
return orders.list();
}
}
public class OrdersModel 

extends LoadableDetachableModel<List<Order>> {
@Inject
private OrderDao orders;
@Override
protected List<Order> load() {
return orders.list();
}
}
public class OrdersModel 

extends LoadableDetachableModel<List<Order>> {
@Inject
private OrderDao orders;
public OrdersModel() {
}
@Override
protected List<Order> load() {
return orders.list();
}
}
public class OrdersModel 

extends LoadableDetachableModel<List<Order>> {
@Inject
private OrderDao orders;
public OrdersModel() {
NonContextual.of(OrdersModel.class).inject(this);
}
@Override
protected List<Order> load() {
return orders.list();
}
}
public class OrdersPage extends WebPage {
public OrdersPage() {
add(new ListView<Order>("items", new OrdersModel()) {
@Override
protected void populateItem(ListItem<Order> item) {
Order o = item.getModelObject();
item.add(new Label("id", o.getId()));
item.add(new Label("name", o.getName()));
item.add(new Label("total", o.getTotal()));
}
});
}
}
public class OrdersPage extends WebPage {
public OrdersPage() {
}
}
public class OrdersPage extends WebPage {
public OrdersPage() {
add(new ListView<Order>("items", new OrdersModel()) {
});
}
}
public class OrdersPage extends WebPage {
public OrdersPage() {
add(new ListView<Order>("items", new OrdersModel()) {
@Override
protected void populateItem(ListItem<Order> item) {
}
});
}
}
public class OrdersPage extends WebPage {
public OrdersPage() {
add(new ListView<Order>("items", new OrdersModel()) {
@Override
protected void populateItem(ListItem<Order> item) {
Order o = item.getModelObject();
item.add(new Label("id", o.getId()));
item.add(new Label("name", o.getName()));
item.add(new Label("total", o.getTotal()));
}
});
}
}
Caused by: org.hibernate.LazyInitializationException: failed to lazily
initialize a collection of role: com.cheesr.entities.Order.items, could
not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throw
at org.hibernate.collection.internal.AbstractPersistentCollection.withT
at org.hibernate.collection.internal.AbstractPersistentCollection.initi
at org.hibernate.collection.internal.AbstractPersistentCollection.read(
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentB
at java.util.Spliterators$IteratorSpliterator.estimateSize(Spliterators
at java.util.Spliterator.getExactSizeIfKnown(Spliterator.java:408)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:511
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.j
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.jav
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234
at java.util.stream.DoublePipeline.collect(DoublePipeline.java:476)
at java.util.stream.DoublePipeline.sum(DoublePipeline.java:388)
at com.cheesr.entities.Order.getTotal(Order.java:94)
at com.cheesr.web.OrdersPage$1.populateItem(OrdersPage.java:22)
at org.apache.wicket.markup.html.list.ListView.onPopulate(ListView.java
at org.apache.wicket.markup.repeater.AbstractRepeater.onBeforeRender(Ab
at org.apache.wicket.Component.internalBeforeRender(Component.java:949)
at org.apache.wicket.Component.beforeRender(Component.java:1017)
at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupConta
... 50 more
LazyInitializationException
failed to lazily initialize a collection of role:
com.cheesr.entities.Order.items, could not initialize proxy
- no Session
LazyInitException: AARGH
Why and how to get rid of them
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class OrderDao implements Serializable {
public void save(Order order) {…}
public List<Order> list() {…}
}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class OrderDao implements Serializable {
public void save(Order order) {…}
public List<Order> list() {…}
}
After dao.list() JPA session ends
@Entity
@Table(name = "Orders")
public class Order implements Serializable {
@Id
@GeneratedValue
private Long id;
private String name;
private String street;
private String zipcode;
private String city;
private String country;
@OneToMany(fetch = FetchType.LAZY,
mappedBy = "order",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
public Long getId() {
return id;
@Entity
@Table(name = "Orders")
public class Order implements Serializable {
@Id
@GeneratedValue
private Long id;
private String name;
private String street;
private String zipcode;
private String city;
private String country;
@OneToMany(fetch = FetchType.LAZY,
mappedBy = "order",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
public Long getId() {
return id;
Generates lazy proxies, resolved
upon request
public class OrdersPage extends WebPage {
public OrdersPage() {
add(new ListView<Order>("items", new OrdersModel()) {
@Override
protected void populateItem(ListItem<Order> item) {
Order o = item.getModelObject();
item.add(new Label("id", o.getId()));
item.add(new Label("name", o.getName()));
item.add(new Label("total", o.getTotal()));
}
});
}
}
public class OrdersPage extends WebPage {
public OrdersPage() {
add(new ListView<Order>("items", new OrdersModel()) {
@Override
protected void populateItem(ListItem<Order> item) {
Order o = item.getModelObject();
item.add(new Label("id", o.getId()));
item.add(new Label("name", o.getName()));
item.add(new Label("total", o.getTotal()));
}
});
}
}
getTotal() requests upon the
proxy: LazyInitException
Fix LazyInitExceptions
Extend transaction for whole request
(using a Servlet 3.0 @WebFilter)
@WebFilter(filterName = "Cheesr",
value = "/*",
initParams = {
@WebInitParam(
name = "applicationClassName",
value = "com.cheesr.web.WicketApplication"),
@WebInitParam(
name = "filterMappingUrlPattern",
value = "/*")
})
public class CheesrFilter extends WicketFilter {
@Override
public void doFilter(ServletRequest req, ServletResponse
super.doFilter(request, response, chain);
}
}
@WebFilter(filterName = "Cheesr",
value = "/*",
initParams = {
@WebInitParam(
name = "applicationClassName",
value = "com.cheesr.web.WicketApplication"),
@WebInitParam(
name = "filterMappingUrlPattern",
value = "/*")
})
public class CheesrFilter extends WicketFilter {
@Transactional
@Override
public void doFilter(ServletRequest req, ServletResponse
super.doFilter(request, response, chain);
}
}
Rolling back a transaction
When you use a reloading model

e.g. CheeseLoadableModel
And you use container managed transactions

@Transactional WicketFilter
Then be careful of unwanted modifications
Form<Cheese> form = new Form<Cheese>("form", cheeseModel) {
@Override
protected void onSubmit() {
Cheese cheese = getModelObject();
if (cheese.getPrice() < 1) {
error("Price must be €1,- or higher");
} else {
cheeseDao.save(cheese);
setResponsePage(Index.class);
}
}
};
add(form);
"No news is good news..."
– Container Managed Transactions
Form<Cheese> form = new Form<Cheese>("form", cheeseModel) {
@Override
protected void onSubmit() {
Cheese cheese = getModelObject();
if (cheese.getPrice() < 1) {
error("Price must be €1,- or higher");
} else {
cheeseDao.save(cheese);
setResponsePage(Index.class);
}
}
};
add(form);
Form<Cheese> form = new Form<Cheese>("form", cheeseModel) {
@Override
protected void onSubmit() {
Cheese cheese = getModelObject();
if (cheese.getPrice() < 1) {
transactionBean.setTransactionRollbackOnly();
error("Price must be €1,- or higher");
} else {
cheeseDao.save(cheese);
setResponsePage(Index.class);
}
}
};
add(form);
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class TransactionBean {
@Resource
private SessionContext context;
public void setTransactionRollbackOnly()
{
context.setRollbackOnly();
}
}
When you use a reloading model

e.g. CheeseLoadableModel
And you use container managed transactions

@Transactional WicketFilter
Then be careful of unwanted modifications

and rollback the transaction
Injection (EJB, CDI)
Conversations (CDI)
JPA
Bean validation
Testing with Arquillian
Bean Validation
Single Point of Definition
Add dependencies
Add validation constraints
Configure Wicket
Add Validators to components
Steps
<!-- BEAN VALIDATION DEPENDENCIES -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-bean-validation</artifactId>
</dependency>
@Entity
@Table(name = "Orders")
public class Order implements Serializable {
@Id
@GeneratedValue
private Long id;
private String name;
private String street;
private String zipcode;
private String city;
private String country;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "order", ca
private List<OrderItem> items = new ArrayList<>();
@Entity
@Table(name = "Orders")
public class Order implements Serializable {
@Id
@GeneratedValue
private Long id;
@NotNull
private String name;
private String street;
private String zipcode;
private String city;
private String country;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "order", ca
private List<OrderItem> items = new ArrayList<>();
@Entity
@Table(name = "Orders")
public class Order implements Serializable {
@Id
@GeneratedValue
private Long id;
@NotNull
private String name;
@Size(min = 3, max = 20)
@NotNull
private String street;
private String zipcode;
private String city;
private String country;
@Entity
@Table(name = "Orders")
public class Order implements Serializable {
@Id
@GeneratedValue
private Long id;
@NotNull
private String name;
@Size(min = 3, max = 20)
@NotNull
private String street;
@Pattern(regexp = "d{4} [A-Z]{2}")
@NotNull
private String zipcode;
private String city;
public void init() {
super.init();
BeanValidationConfiguration beanValidation =
new BeanValidationConfiguration();
beanValidation.configure(this);
CdiConfiguration cdiConfiguration =
new CdiConfiguration();
cdiConfiguration
.setPropagation(ConversationPropagation.ALL);
cdiConfiguration.configure(this);
getComponentInstantiationListeners().add(
new JavaEEComponentInjector(this,
new WildflyWicketJndiNamingStrategy()));
mountPage("/checkout", CheckoutPage.class);
mountPage("/orders", OrdersPage.class);
}
TextField<String> nameField =
new TextField<>("name", PropertyModel.of(this, "order.nam
form.add(nameField);
TextField<String> streetField =
new TextField<>("street", PropertyModel.of(this, "order.s
form.add(streetField);
TextField<String> nameField =
new TextField<>("name", PropertyModel.of(this, "order.nam
nameField.add(new PropertyValidator<>());
form.add(nameField);
TextField<String> streetField =
new TextField<>("street", PropertyModel.of(this, "order.s
form.add(streetField);
TextField<String> nameField =
new TextField<>("name", PropertyModel.of(this, "order.nam
nameField.add(new PropertyValidator<>());
form.add(nameField);
TextField<String> streetField =
new TextField<>("street", PropertyModel.of(this, "order.s
streetField.add(new PropertyValidator<>());
form.add(streetField);
add wicket-bean-validation and
javax.validation:validation-api to project
configure BeanValidationConfiguration in init()
add PropertyValidator to fields
Injection (EJB, CDI)
Conversations (CDI)
JPA
Bean validation
Testing with Arquillian
Testing with WicketTester
public class TestIndex {
private WicketTester tester;
@Before
public void setUp() {
WicketApplication app = new WicketApplication();
tester = new WicketTester(app);
}
@Test
public void homepageRendersSuccessfully() {
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
}
}
• No bean manager
• No data source
• No persistence context
• No transactions
• No EJBs
NO
TESTS
Arquillian
No more mocks. No more container lifecycle
and deployment hassles. Just real tests!
Add Arquillian dependencies 

to project
Build deployable archive

with all necessary resources
Create a test case
Execute test case with Arquillian
Steps
<!-- ARQUILLIAN DEPENDENCY FOR TESTING -->
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<!-- ARQUILLIAN DEPENDENCY FOR TESTING -->
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.descriptors</groupId>
<artifactId>shrinkwrap-descriptors-impl-javaee</artifact
<scope>test</scope>
</dependency>
<!-- ARQUILLIAN DEPENDENCY FOR TESTING -->
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.descriptors</groupId>
<artifactId>shrinkwrap-descriptors-impl-javaee</artifact
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven</artifactId>
<scope>test</scope>
</dependency>
Add Arquillian dependencies 

to project
Build deployable archive

with all necessary resources
Create a test case
Execute test case with Arquillian
Steps
public class TestIndex {
private WicketTester tester;
@Before
public void setUp() {
WicketApplication app = new WicketApplication();
tester = new WicketTester(app);
}
@Test
public void homepageRendersSuccessfully() {
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
}
}
@RunWith(Arquillian.class)
public class TestIndex {
private WicketTester tester;
@Before
public void setUp() {
WicketApplication app = new WicketApplication();
tester = new WicketTester(app);
}
@Test
public void homepageRendersSuccessfully() {
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
}
}
@RunWith(Arquillian.class)
public class TestIndex {
@Deployment
public static WebArchive deployment() {…}
private WicketTester tester;
@Before
public void setUp() {
WicketApplication app = new WicketApplication();
tester = new WicketTester(app);
}
@Test
public void homepageRendersSuccessfully() {
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
}
}
@Deployment
public static WebArchive deployment() {
File[] dependencies =
Maven.configureResolver()
.workOffline()
.loadPomFromFile("pom.xml")
.importCompileAndRuntimeDependencies()
.resolve()
.withTransitivity()
.as(File.class);
}
@Deployment
public static WebArchive deployment() {
File[] dependencies =
Maven.configureResolver()
.workOffline()
.loadPomFromFile("pom.xml")
.importCompileAndRuntimeDependencies()
.resolve()
.withTransitivity()
.as(File.class);
WebArchive war = ShrinkWrap
.create(WebArchive.class)
.addAsResource(new File("target/classes"), "")
.addAsLibraries(dependencies)
.addAsWebInfResource(
new File("src/main/webapp/WEB-INF/beans.xml"))
.addAsWebInfResource(
new File("src/main/webapp/WEB-INF/cheesr-ds.xml")
return war;
}
6ea1e1a7-7f07-4318-8f70-ec7b8d5edbcc.war:
/WEB-INF/
/WEB-INF/lib/
/WEB-INF/lib/annotations-3.0.0.jar
/WEB-INF/lib/wicketstuff-javaee-inject-6.17.0.jar
/WEB-INF/lib/javax.inject-1.jar
/WEB-INF/lib/wicket-cdi-1.1-6.18.0.jar
/WEB-INF/lib/cglib-2.2.2.jar
/WEB-INF/lib/fest-util-1.1.6.jar
/WEB-INF/lib/wicket-ioc-6.18.0.jar
/WEB-INF/lib/wicket-bean-validation-6.18.0.jar
/WEB-INF/lib/wicket-request-6.18.0.jar
/WEB-INF/lib/log4j-1.2.17.jar
/WEB-INF/lib/asm-3.3.1.jar
/WEB-INF/lib/fest-assert-1.4.jar
/WEB-INF/lib/validation-api-1.1.0.Final.jar
/WEB-INF/lib/slf4j-log4j12-1.7.7.jar
/WEB-INF/lib/slf4j-api-1.7.7.jar
/WEB-INF/lib/jcl-over-slf4j-1.7.7.jar
/WEB-INF/lib/wicket-core-6.18.0.jar
/WEB-INF/lib/wicket-util-6.18.0.jar
/WEB-INF/cheesr-ds.xml
/WEB-INF/classes/
/WEB-INF/classes/wildfly-doesnt-need-log4j.properties
/WEB-INF/classes/META-INF/
/WEB-INF/classes/META-INF/persistence.xml
/WEB-INF/classes/com/
/WEB-INF/classes/com/cheesr/
/WEB-INF/classes/com/cheesr/domain/
/WEB-INF/classes/com/cheesr/domain/Cart.class
/WEB-INF/classes/com/cheesr/domain/MessageOfTheDay.class
/WEB-INF/classes/com/cheesr/web/
/WEB-INF/classes/com/cheesr/web/CheckoutPage$2.class
/WEB-INF/classes/com/cheesr/web/Index$2$1.class
/WEB-INF/classes/com/cheesr/web/OrdersPage.class
/WEB-INF/classes/com/cheesr/web/WicketApplication.class
/WEB-INF/classes/com/cheesr/web/Index$1$1.class
/WEB-INF/classes/com/cheesr/web/Index.html
/WEB-INF/classes/com/cheesr/web/WicketApplication$WildflyWicketJndiNamingStrategy.class
/WEB-INF/classes/com/cheesr/web/Index$2.class
/WEB-INF/classes/com/cheesr/web/CheckoutPage.class
/WEB-INF/classes/com/cheesr/web/CheckoutPage.html
/WEB-INF/classes/com/cheesr/web/Index.class
/WEB-INF/classes/com/cheesr/web/CheesrFilter.class
/WEB-INF/classes/com/cheesr/web/MessageModel.class
/WEB-INF/classes/com/cheesr/web/Index$3.class
/WEB-INF/classes/com/cheesr/web/OrdersModel.class
Add Arquillian dependencies 

to project
Build deployable archive

with all necessary resources
Create a test case
Execute test case with Arquillian
Steps
Add Arquillian dependencies 

to project
Build deployable archive

with all necessary resources
Create a test case
Execute test case with Arquillian
Steps
@Inject
private Conversation conversation;
@EJB
private CheeseDao cheeses;
@Inject
private Cart cart;
@Test
public void addCheeseToCart() {
}
public void addCheeseToCart() {
}
public void addCheeseToCart() {
Cheese edam = cheeses.byCode("edam");
}
public void addCheeseToCart() {
Cheese edam = cheeses.byCode("edam");
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
}
public void addCheeseToCart() {
Cheese edam = cheeses.byCode("edam");
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
tester.assertModelValue("cheese:1", edam);
}
public void addCheeseToCart() {
Cheese edam = cheeses.byCode("edam");
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
tester.assertModelValue("cheese:1", edam);
tester.clickLink("cheese:1:add");
assertThat(cart.getItems().size(), is(1));
tester.assertModelValue("item:0", edam);
}
public void addCheeseToCart() {
Cheese edam = cheeses.byCode("edam");
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
tester.assertModelValue("cheese:1", edam);
tester.clickLink("cheese:1:add");
assertThat(cart.getItems().size(), is(1));
tester.assertModelValue("item:0", edam);
tester.clickLink("cheese:1:add");
assertThat(cart.getItems().size(), is(2));
assertThat(cart.getItems().get(0), is(edam));
assertThat(cart.getItems().get(1), is(edam));
}
public void addCheeseToCart() {
Cheese edam = cheeses.byCode("edam");
tester.startPage(Index.class);
tester.assertRenderedPage(Index.class);
tester.assertModelValue("cheese:1", edam);
tester.clickLink("cheese:1:add");
assertThat(cart.getItems().size(), is(1));
tester.assertModelValue("item:0", edam);
tester.clickLink("cheese:1:add");
assertThat(cart.getItems().size(), is(2));
assertThat(cart.getItems().get(0), is(edam));
assertThat(cart.getItems().get(1), is(edam));
tester.clickLink("checkout");
tester.assertRenderedPage(CheckoutPage.class);
}
with Arquillian you can test Wicket pages with JPA, CDI,
EJB
add Arquillian dependencies to POM,
add arquillian.xml for container connection
create a deployment
write and run your tests
Injection (EJB, CDI)
Conversations (CDI)
JPA
Bean validation
Arquillian
Wicket and Java EE?
Questions?

More Related Content

What's hot

That Goes Without Alpha-Num (or Does It ?) all your base10 are belong to us
That Goes Without Alpha-Num (or Does It ?) all your base10 are belong to usThat Goes Without Alpha-Num (or Does It ?) all your base10 are belong to us
That Goes Without Alpha-Num (or Does It ?) all your base10 are belong to ustakesako
 
2018 PyCon Korea - Ring
2018 PyCon Korea - Ring2018 PyCon Korea - Ring
2018 PyCon Korea - RingYunWon Jeong
 
JNI - Java & C in the same project
JNI - Java & C in the same projectJNI - Java & C in the same project
JNI - Java & C in the same projectKarol Wrótniak
 
Do we need Unsafe in Java?
Do we need Unsafe in Java?Do we need Unsafe in Java?
Do we need Unsafe in Java?Andrei Pangin
 
Comparative Genomics with GMOD and BioPerl
Comparative Genomics with GMOD and BioPerlComparative Genomics with GMOD and BioPerl
Comparative Genomics with GMOD and BioPerlJason Stajich
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 SpringKiyotaka Oku
 
Systems and methods for visual presentation and selection of ivr menu
Systems and methods for visual presentation and selection of ivr menuSystems and methods for visual presentation and selection of ivr menu
Systems and methods for visual presentation and selection of ivr menuTal Lavian Ph.D.
 
穏やかにファイルを削除する
穏やかにファイルを削除する穏やかにファイルを削除する
穏やかにファイルを削除する鉄次 尾形
 

What's hot (10)

That Goes Without Alpha-Num (or Does It ?) all your base10 are belong to us
That Goes Without Alpha-Num (or Does It ?) all your base10 are belong to usThat Goes Without Alpha-Num (or Does It ?) all your base10 are belong to us
That Goes Without Alpha-Num (or Does It ?) all your base10 are belong to us
 
My Doc of geth
My Doc of gethMy Doc of geth
My Doc of geth
 
2018 PyCon Korea - Ring
2018 PyCon Korea - Ring2018 PyCon Korea - Ring
2018 PyCon Korea - Ring
 
JNI - Java & C in the same project
JNI - Java & C in the same projectJNI - Java & C in the same project
JNI - Java & C in the same project
 
Do we need Unsafe in Java?
Do we need Unsafe in Java?Do we need Unsafe in Java?
Do we need Unsafe in Java?
 
Comparative Genomics with GMOD and BioPerl
Comparative Genomics with GMOD and BioPerlComparative Genomics with GMOD and BioPerl
Comparative Genomics with GMOD and BioPerl
 
Unit testing pig
Unit testing pigUnit testing pig
Unit testing pig
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 Spring
 
Systems and methods for visual presentation and selection of ivr menu
Systems and methods for visual presentation and selection of ivr menuSystems and methods for visual presentation and selection of ivr menu
Systems and methods for visual presentation and selection of ivr menu
 
穏やかにファイルを削除する
穏やかにファイルを削除する穏やかにファイルを削除する
穏やかにファイルを削除する
 

Similar to Apache Wicket and Java EE sitting in a tree

Avro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSONAvro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSONAlexandre Victoor
 
¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?jaespinmora
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...Mateusz Zalewski
 
Matching Game In Java
Matching Game In JavaMatching Game In Java
Matching Game In Javacmkandemir
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsBastian Feder
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEDarwin Durand
 
The Ring programming language version 1.5.3 book - Part 71 of 184
The Ring programming language version 1.5.3 book - Part 71 of 184The Ring programming language version 1.5.3 book - Part 71 of 184
The Ring programming language version 1.5.3 book - Part 71 of 184Mahmoud Samir Fayed
 
Corinna-2023.pptx
Corinna-2023.pptxCorinna-2023.pptx
Corinna-2023.pptxCurtis Poe
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196Mahmoud Samir Fayed
 
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze..."Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...Mateusz Zalewski
 
Project hotel on hotel management fo
Project  hotel on hotel management foProject  hotel on hotel management fo
Project hotel on hotel management foSunny Singhania
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189Mahmoud Samir Fayed
 
The Ring programming language version 1.4.1 book - Part 16 of 31
The Ring programming language version 1.4.1 book - Part 16 of 31The Ring programming language version 1.4.1 book - Part 16 of 31
The Ring programming language version 1.4.1 book - Part 16 of 31Mahmoud Samir Fayed
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.Mike Fogus
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mockskenbot
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETTomas Jansson
 
Vaadin 8 - Data Binding with Binder
Vaadin 8 - Data Binding with BinderVaadin 8 - Data Binding with Binder
Vaadin 8 - Data Binding with BinderPeter Lehto
 

Similar to Apache Wicket and Java EE sitting in a tree (20)

Avro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSONAvro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSON
 
¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
 
J slider
J sliderJ slider
J slider
 
Matching Game In Java
Matching Game In JavaMatching Game In Java
Matching Game In Java
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 
Groovy
GroovyGroovy
Groovy
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
 
The Ring programming language version 1.5.3 book - Part 71 of 184
The Ring programming language version 1.5.3 book - Part 71 of 184The Ring programming language version 1.5.3 book - Part 71 of 184
The Ring programming language version 1.5.3 book - Part 71 of 184
 
Corinna-2023.pptx
Corinna-2023.pptxCorinna-2023.pptx
Corinna-2023.pptx
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
 
Jersey Guice AOP
Jersey Guice AOPJersey Guice AOP
Jersey Guice AOP
 
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze..."Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
"Kto to pisał?!... A, to ja.", czyli sposoby, żeby znienawidzić siebie z prze...
 
Project hotel on hotel management fo
Project  hotel on hotel management foProject  hotel on hotel management fo
Project hotel on hotel management fo
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189
 
The Ring programming language version 1.4.1 book - Part 16 of 31
The Ring programming language version 1.4.1 book - Part 16 of 31The Ring programming language version 1.4.1 book - Part 16 of 31
The Ring programming language version 1.4.1 book - Part 16 of 31
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
 
Vaadin 8 - Data Binding with Binder
Vaadin 8 - Data Binding with BinderVaadin 8 - Data Binding with Binder
Vaadin 8 - Data Binding with Binder
 

More from Martijn Dashorst

HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0
HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0
HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0Martijn Dashorst
 
From Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud DeploymentsFrom Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud DeploymentsMartijn Dashorst
 
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQLConverting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQLMartijn Dashorst
 
Solutions for when documentation fails
Solutions for when documentation fails Solutions for when documentation fails
Solutions for when documentation fails Martijn Dashorst
 
Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8Martijn Dashorst
 
Java Serialization Deep Dive
Java Serialization Deep DiveJava Serialization Deep Dive
Java Serialization Deep DiveMartijn Dashorst
 
Scrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijsScrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijsMartijn Dashorst
 
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)Martijn Dashorst
 
Wicket 10 years and beyond
Wicket   10 years and beyond Wicket   10 years and beyond
Wicket 10 years and beyond Martijn Dashorst
 
Vakmanschap is meesterschap
Vakmanschap is meesterschapVakmanschap is meesterschap
Vakmanschap is meesterschapMartijn Dashorst
 
Keep your Wicket application in production
Keep your Wicket application in productionKeep your Wicket application in production
Keep your Wicket application in productionMartijn Dashorst
 
Wicket In Action - oredev2008
Wicket In Action - oredev2008Wicket In Action - oredev2008
Wicket In Action - oredev2008Martijn Dashorst
 
Guide To Successful Graduation at Apache
Guide To Successful Graduation at ApacheGuide To Successful Graduation at Apache
Guide To Successful Graduation at ApacheMartijn Dashorst
 

More from Martijn Dashorst (20)

HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0
HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0
HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0
 
From Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud DeploymentsFrom Floppy Disks to Cloud Deployments
From Floppy Disks to Cloud Deployments
 
SOLID principles
SOLID principlesSOLID principles
SOLID principles
 
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQLConverting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
 
Solutions for when documentation fails
Solutions for when documentation fails Solutions for when documentation fails
Solutions for when documentation fails
 
Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8Whats up with wicket 8 and java 8
Whats up with wicket 8 and java 8
 
Code review drinking game
Code review drinking gameCode review drinking game
Code review drinking game
 
Java Serialization Deep Dive
Java Serialization Deep DiveJava Serialization Deep Dive
Java Serialization Deep Dive
 
Code review drinking game
Code review drinking gameCode review drinking game
Code review drinking game
 
Scrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijsScrum: van praktijk naar onderwijs
Scrum: van praktijk naar onderwijs
 
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
 
De schone coder
De schone coderDe schone coder
De schone coder
 
Wicket 10 years and beyond
Wicket   10 years and beyond Wicket   10 years and beyond
Wicket 10 years and beyond
 
The State of Wicket
The State of WicketThe State of Wicket
The State of Wicket
 
Wicket 2010
Wicket 2010Wicket 2010
Wicket 2010
 
Vakmanschap is meesterschap
Vakmanschap is meesterschapVakmanschap is meesterschap
Vakmanschap is meesterschap
 
Keep your Wicket application in production
Keep your Wicket application in productionKeep your Wicket application in production
Keep your Wicket application in production
 
Wicket In Action - oredev2008
Wicket In Action - oredev2008Wicket In Action - oredev2008
Wicket In Action - oredev2008
 
Guide To Successful Graduation at Apache
Guide To Successful Graduation at ApacheGuide To Successful Graduation at Apache
Guide To Successful Graduation at Apache
 
Wicket In Action
Wicket In ActionWicket In Action
Wicket In Action
 

Recently uploaded

The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
software engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxsoftware engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxnada99848
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 

Recently uploaded (20)

The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
software engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptxsoftware engineering Chapter 5 System modeling.pptx
software engineering Chapter 5 System modeling.pptx
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 

Apache Wicket and Java EE sitting in a tree

  • 1. Apache Wicket
 and Java EE sitting in a tree Martijn Dashorst
 topicus onderwijs APACHE WICKET
  • 3. servlet 3 JSF 2 EJB 3.1 JPA 2 JSP CDI JTA Bean Validation JAX-WS JAX-RPC JAXR SAAJ JAX-RS JAXB JMS JAAS JASPIC JACC JCA Java Mail JSR 88 JSR 77 RMI JNDI Java EE web profile
  • 5. servlet 3 JSF 2 EJB 3.1 JPA 2 JSP CDI JTA Bean Validation JAX-WS JAX-RPC JAXR SAAJ JAX-RS JAXB JMS JAAS JASPIC JACC JCA Java Mail JSR 88 JSR 77 RMI JNDI Java EE web profile
  • 6. servlet 3 JSF 2 EJB 3.1 JPA 2 JSP CDI JTA Bean Validation JAX-WS JAX-RPC JAXR SAAJ JAX-RS JAXB JMS JAAS JASPIC JACC JCA Java Mail JSR 88 JSR 77 RMI JNDI Java EE web profile Arquillian
  • 8. wicket |ˈwɪkɪt| noun 1 Cricket each of the sets of three stumps with two bails across the top at either end of the pitch, defended by a batsman. • the prepared strip of ground between two sets of stumps. when they inspected the wicket, they found it being rolled by some prisoners. • the dismissal of a batsman; each of ten dismissals regarded as marking a division of a side's innings: Darlington won by four wickets. 2 (also wicket door or wicket gate)a small door or gate, especially one beside or in a larger one. • N. Amer. an opening in a door or wall, often fitted with glass or a grille and used for selling tickets or a similar purpose. 3 N. Amer. a croquet hoop. PHRASES at the wicket Cricket 1 batting: the batsman remained at the wicket. 2 by the wicketkeeper: he was caught at the wicket chasing a wide one. keep wicket Cricket be a wicketkeeper. lose a wicket Cricket (of the batting side) have a batsman dismissed. the tourists lost their last seven wickets for 94. a sticky wicket Cricket a pitch that has been drying after rain and is difficult to bat on. • informal a tricky or awkward situation: I might be on a sticky wicket if I used that line. over the wicket Cricket (referring to which side of the wicket a bowler runs when bowling) to the left of the wicket if a right-handed bowler and the right of the wicket if a left-handed bowler. round the wicket Cricket (referring to which side of the wicket a bowler runs when bowling) to the right of the wicket if a right-handed bowler and the left of the wicket if a left-handed bowler. take a wicket Cricket (of a bowler or a fielding side) dismiss a batsman. ORIGIN Middle English (in the sense ‘small door or grille’): from Anglo-Norman French and Old Northern French wiket; origin uncertain, usually referred to the Germanic root of Old Norse vīkja ‘to turn, move’. Cricket senses date from the late 17th cent.
  • 9. wicket |ˈwɪkɪt| noun 1 a component oriented, open source, Java web application framework
  • 13. Injection (EJB, CDI) Conversations (CDI) JPA Bean validation Arquillian
  • 15.
  • 16.
  • 17. 1. Setup project 2. Add 'domain layer' 3. Add components First steps
  • 18. 1. setup the project
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 29.
  • 30.
  • 31.
  • 32. package com.cheesr.web; import org.apache.wicket.markup.html.WebPage; public class Index extends WebPage { public Index() { } }
  • 33. package com.cheesr.web; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.protocol.http.WebApplica public class WicketApplication extends WebApplica @Override public Class<? extends WebPage> getHomePage() { return Index.class; } @Override public void init() { super.init(); } }
  • 34.
  • 35.
  • 36. 2. Add 'domain model'
  • 39. package com.cheesr.dao; public class CheeseDao { public List<Cheese> getCheeses() { } }
  • 40. package com.cheesr.dao; /*...*/ public class CheeseDao { public List<Cheese> getCheeses() { return asList(); } }
  • 41. package com.cheesr.dao; /*...*/ public class CheeseDao { public List<Cheese> getCheeses() { return asList( new Cheese()); } }
  • 42. package com.cheesr.dao; /*...*/ public class CheeseDao { public List<Cheese> getCheeses() { return asList( new Cheese( "Gouda", "Named after the Dutch town of Gouda, j", 1.99)); } }
  • 43. package com.cheesr.dao; /*...*/ public class CheeseDao { public List<Cheese> getCheeses() { return asList( new Cheese( "Gouda", "Named after the Dutch town of Gouda, j", 1.99), new Cheese( "Edam", "This is a pressed, semi-hard to hard c", 2.99)); } }
  • 44. package com.cheesr.dao; /*...*/ public class CheeseDao { public List<Cheese> getCheeses() { return asList( new Cheese( "Gouda", "Named after the Dutch town of Gouda, j", 1.99), new Cheese( "Edam", "This is a pressed, semi-hard to hard c", 2.99), new Cheese( "Camembert", "A very famous French cheese, Camembert", 3.99)); } }
  • 46. package com.cheesr.dao; public class OrderDao { public void save(Order order) { } }
  • 47. package com.cheesr.dao; public class OrderDao { private List<Order> orders = new ArrayList<>(); public void save(Order order) { } }
  • 48. package com.cheesr.dao; public class OrderDao { private List<Order> orders = new ArrayList<>(); public void save(Order order) { orders.add(order); } }
  • 49. package com.cheesr.dao; public class OrderDao { private List<Order> orders = new ArrayList<>(); public void save(Order order) { orders.add(order); } public List<Order> list() { } }
  • 50. package com.cheesr.dao; public class OrderDao { private List<Order> orders = new ArrayList<>(); public void save(Order order) { orders.add(order); } public List<Order> list() { return Collections.unmodifiableList(orders); } }
  • 52.
  • 53. <div class="cheese"> <h3>Gouda</h3> <p>Named after the Dutch town of Gouda, just ou <p> <span>$1.99</span> <a href="#">Add to cart</a> </p> </div>
  • 54. <div wicket:id="cheese" class="cheese"> <h3 wicket:id="name">Gouda</h3> <p wicket:id="description">Named after the Dutc <p> €<span wicket:id="price">1.99</span> <a href="#">Add to cart</a> </p> </div>
  • 55. public class Index extends WebPage { public Index() { } }
  • 56. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() { } }
  • 57. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); } }
  • 58. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) { }); } }
  • 59. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { } }); } }
  • 60. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("description", c.getDescriptio item.add(new Label("price", c.getPrice())); } }); } }
  • 61.
  • 63. <h3>Your Selection</h3> <table> <tbody> <tr wicket:id="item"> <td wicket:id="name">Gouda</td> <td>€<span wicket:id="price">1.99</span></td> <td><a href="#">remove</a></td> </tr> </tbody> <tfoot> <tr class="total"> <th>Total</th> <td>$1.99</td> <td>&nbsp;</td> </tr> </tfoot> </table>
  • 64. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); } }
  • 65. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); } }
  • 66. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) { }); } }
  • 67. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) { @Override protected void populateItem(ListItem<Cheese> item) { } }); } }
  • 68. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); } }); } }
  • 69. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("price", c.getPrice())); } }); } }
  • 70.
  • 71. <div wicket:id="cheese" class="cheese"> <h3 wicket:id="name">Gouda</h3> <p wicket:id="description">Named after the Dutc <p> €<span wicket:id="price">1.99</span> <a href="#">Add to cart</a> </p> </div>
  • 72. <div wicket:id="cheese" class="cheese"> <h3 wicket:id="name">Gouda</h3> <p wicket:id="description">Named after the Dutc <p> €<span wicket:id="price">1.99</span> <a wicket:id="price" href="#">Add to cart</a> </p> </div>
  • 73. add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("description", c.getDescription())) item.add(new Label("price", c.getPrice())); } });
  • 74. add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("description", c.getDescription())) item.add(new Label("price", c.getPrice())); item.add(new Link<Cheese>("price", item.getModel())); } });
  • 75. add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("description", c.getDescription())) item.add(new Label("price", c.getPrice())); item.add(new Link<Cheese>("price", item.getModel()) { }); } });
  • 76. add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("description", c.getDescription())) item.add(new Label("price", c.getPrice())); item.add(new Link<Cheese>("price", item.getModel()) { @Override public void onClick() { } }); } });
  • 77. add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("description", c.getDescription())) item.add(new Label("price", c.getPrice())); item.add(new Link<Cheese>("price", item.getModel()) { @Override public void onClick() { Cheese cheese = getModelObject(); } }); } });
  • 78. add(new ListView<Cheese>("cheese", cheeses) { @Override protected void populateItem(ListItem<Cheese> item) { Cheese c = item.getModelObject(); item.add(new Label("name", c.getName())); item.add(new Label("description", c.getDescription())) item.add(new Label("price", c.getPrice())); item.add(new Link<Cheese>("price", item.getModel()) { @Override public void onClick() { Cheese cheese = getModelObject(); cart.getItems().add(cheese); } }); } });
  • 79. Injection (EJB, CDI) Conversations (CDI) JPA Bean validation Testing with Arquillian
  • 81. Add EJB dependencies 
 to project Make DAOs EJBs Inject DAOs Steps
  • 82. <dependencies> <!-- EJB DEPENDENCIES --> <dependency> <groupId>org.jboss.spec.javax.ejb</groupId> <artifactId>jboss-ejb-api_3.2_spec</artifactId> <scope>provided</scope> </dependency> … </dependencies>
  • 83. Add EJB dependencies 
 to project Make DAOs EJBs Inject DAOs Steps
  • 84. public class CheeseDao { public List<Cheese> getCheeses() {…} } public class OrderDao { public void save(Order order) {…} public List<Order> list() {…} } public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() {…} }
  • 85. public class CheeseDao { public List<Cheese> getCheeses() {…} } public class OrderDao { public void save(Order order) {…} public List<Order> list() {…} } public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() {…} }
  • 86. @Stateless public class CheeseDao { public List<Cheese> getCheeses() {…} } public class OrderDao { public void save(Order order) {…} public List<Order> list() {…} } public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() {…} }
  • 87. @Stateless public class CheeseDao { public List<Cheese> getCheeses() {…} } @Stateless public class OrderDao { public void save(Order order) {…} public List<Order> list() {…} } public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); public Index() {…} }
  • 88. @Stateless public class CheeseDao { public List<Cheese> getCheeses() {…} } @Stateless public class OrderDao { public void save(Order order) {…} public List<Order> list() {…} } public class Index extends WebPage { private CheeseDao cheeseDao; public Index() {…} }
  • 89. Add EJB dependencies 
 to project Make DAOs EJBs Inject DAOs Steps
  • 90. @Stateless public class CheeseDao { public List<Cheese> getCheeses() {…} } @Stateless public class OrderDao { public void save(Order order) {…} public List<Order> list() {…} } public class Index extends WebPage { @EJB private CheeseDao cheeseDao; public Index() {…} }
  • 91. 21:20:55,305 Processing weld deployment cheesr.war 21:20:55,313 JNDI bindings for session bean named CheeseDao in deployment unit deployment "cheesr.war" are as follows: java:global/cheesr/CheeseDao!com.cheesr.dao.CheeseDao java:app/cheesr/CheeseDao!com.cheesr.dao.CheeseDao java:module/CheeseDao!com.cheesr.dao.CheeseDao java:global/cheesr/CheeseDao java:app/cheesr/CheeseDao java:module/CheeseDao 21:20:55,335 Starting Services for CDI deployment: cheesr.war 21:20:55,340 Starting weld service for deployment cheesr.war
  • 92.
  • 93. public class Index extends WebPage { @EJB private CheeseDao cheeseDao; private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) } }
  • 94. public class Index extends WebPage { @EJB private CheeseDao cheeseDao; private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) } }
  • 95. Wicket is unmanaged, container doesn't know about Pages, Components, etc.
  • 96.
  • 97. <dependencies> <!-- EJB DEPENDENCIES --> <dependency> <groupId>org.jboss.spec.javax.ejb</groupId> <artifactId>jboss-ejb-api_3.2_spec</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.wicketstuff</groupId> <artifactId>wicketstuff-javaee-inject</artifactId> <version>6.17.0</version> </dependency> </dependencies>
  • 98. public class WicketApplication extends WebApplication { @Override public Class< ? extends WebPage> getHomePage() { return Index.class; } @Override public void init() { super.init(); } }
  • 99. public class WicketApplication extends WebApplication { @Override public Class< ? extends WebPage> getHomePage() { return Index.class; } @Override public void init() { super.init(); getComponentInstantiationListeners() .add(new JavaEEComponentInjector(this)); } }
  • 100.
  • 101. • add EJB dependency and wicketstuff- javaee-inject dependency • make DAOs EJBs • configure component instantiation listener • now you can use @EJB injection
  • 102. Using CDI for injection
  • 103. <dependencies> <!-- CDI DEPENDENCIES --> <dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> </dependency> <dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-cdi-1.1</artifactId> <version>6.18.0</version> </dependency> </dependencies>
  • 104. public class WicketApplication extends WebApplication { @Override public void init() { super.init(); } }
  • 105. public class WicketApplication extends WebApplication { @Override public void init() { super.init(); CdiConfiguration cdiConfiguration = new CdiConfiguration(); cdiConfiguration.configure(this); } }
  • 106. @ApplicationScoped public class MessageOfTheDay { public String getMessage() { return "What happens to the hole when the cheese is go } }
  • 107. public class Index extends WebPage { @EJB private CheeseDao cheeseDao; public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) } }
  • 108. public class Index extends WebPage { @EJB private CheeseDao cheeseDao; @Inject private MessageOfTheDay message; public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) } }
  • 109. public class Index extends WebPage { @EJB private CheeseDao cheeseDao; @Inject private MessageOfTheDay message; public Index() { add(new Label("message", message.getMessage())); List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) } }
  • 110.
  • 112. public class MessageModel extends LoadableDetachableModel<String> { @Inject private MessageOfTheDay messages; @Override protected String load() { return messages.getMessage(); } }
  • 113. Caused by: java.lang.NullPointerException at com.cheesr.web.MessageModel.load(MessageModel.java:15) [:] at com.cheesr.web.MessageModel.load(MessageModel.java:1) [:] at org.apache.wicket.model.LoadableDetachableModel.getObject( at org.apache.wicket.Component.getDefaultModelObject(Componen ... 55 more
  • 114. public class MessageModel extends LoadableDetachableModel<String> { @Inject private MessageOfTheDay messages; @Override protected String load() { return messages.getMessage(); } }
  • 115. public class MessageModel extends LoadableDetachableModel<String> { @Inject private MessageOfTheDay messages; public MessageModel() { NonContextual.of(MessageModel.class).inject(this); } @Override protected String load() { return messages.getMessage(); } }
  • 116. • Add wicket-cdi-1.1 and javax.cdi-api • Configure Wicket's CdiConfiguration • Use @Inject injection • Use NonContextual in non-managed objects
  • 117. Injection (EJB, CDI) Conversations (CDI) JPA Bean validation Testing with Arquillian
  • 118. 4. Navigate to Checkout 5. Implement Checkout 6. Make Cart Conversation Scoped Next steps
  • 119. 4. navigate to checkout
  • 120.
  • 121.
  • 122.
  • 125. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) } }
  • 126. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) add(new Link<Void>("checkout") {}); } }
  • 127. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) add(new Link<Void>("checkout") { @Override public void onClick() { } }); } }
  • 128. public class Index extends WebPage { private CheeseDao cheeseDao = new CheeseDao(); private Cart cart = new Cart(); public Index() { List<Cheese> cheeses = cheeseDao.getCheeses(); add(new ListView<Cheese>("cheese", cheeses) {…}); add(new ListView<Cheese>("item", cart.getItems()) {…}) add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } }
  • 129. public class CheckoutPage extends WebPage { private Cart cart = new Cart(); public CheckoutPage(Cart cart) { this.cart = cart; } }
  • 131.
  • 132. <form > <h3>Check out</h3> <p>Please enter your billing address.</p> <table> <tr> <th>Name</th> <td><input type="text" /></td> </tr> <tr> <th>Street</th> <td><input type="text" /></td> </tr> <tr> <th>Zipcode</th> <td><input type="text" /></td> </tr> <tr> <th>City</th> <td><input type="text" /></td> </tr>
  • 133. <form wicket:id="form"> <h3>Check out</h3> <p>Please enter your billing address.</p> <table> <tr> <th>Name</th> <td><input type="text" /></td> </tr> <tr> <th>Street</th> <td><input type="text" /></td> </tr> <tr> <th>Zipcode</th> <td><input type="text" /></td> </tr> <tr> <th>City</th> <td><input type="text" /></td> </tr>
  • 134. public class CheckoutPage extends WebPage { private Cart cart; public CheckoutPage(Cart cart) { this.cart = cart; } }
  • 135. public class CheckoutPage extends WebPage { private Cart cart; public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") {}; add(form); } }
  • 136. public class CheckoutPage extends WebPage { private Cart cart; public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { } }; add(form); } }
  • 137. public class CheckoutPage extends WebPage { private Cart cart; private Order order = new Order(); public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { } }; add(form); } }
  • 138. public class CheckoutPage extends WebPage { private Cart cart; private Order order = new Order(); @EJB private OrderDao orders; public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { } }; add(form); } }
  • 139. public class CheckoutPage extends WebPage { … public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { } }; add(form); } }
  • 140. public class CheckoutPage extends WebPage { … public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) { } } }; add(form); } }
  • 141. public class CheckoutPage extends WebPage { … public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) { OrderItem item = new OrderItem(); item.setOrder(order); item.setCheese(cheese); order.getItems().add(item); } } }; add(form); } }
  • 142. public class CheckoutPage extends WebPage { … public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) { OrderItem item = new OrderItem(); item.setOrder(order); item.setCheese(cheese); order.getItems().add(item); } orders.save(order); } }; add(form); } }
  • 143. 6. make Cart 
 Conversation Scoped
  • 144. What does the navigation between shopping and checkout look like?
  • 145. public class Index extends WebPage { public Index() { … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } } public class CheckoutPage extends WebPage { private Cart cart; public CheckoutPage(Cart cart) { this.cart = cart; … } }
  • 146. public class Index extends WebPage { public Index() { … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } } public class CheckoutPage extends WebPage { private Cart cart; public CheckoutPage(Cart cart) { this.cart = cart; … } }
  • 147. public class Index extends WebPage { public Index() { … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } } public class CheckoutPage extends WebPage { private Cart cart; public CheckoutPage(Cart cart) { this.cart = cart; … } } Cart should be
 conversation scoped
  • 148. public class Cart implements Serializable { public Cart() { } public void setItems(List<Cheese> items) { this.items = items; } public List<Cheese> getItems() { return items; } public double getTotal() { return items.stream().mapToDouble(Cheese::getPrice).su } }
  • 149. @ConversationScoped public class Cart implements Serializable { private List<Cheese> items = new ArrayList<>(); public Cart() { } public void setItems(List<Cheese> items) { this.items = items; } public List<Cheese> getItems() { return items; } public double getTotal() { return items.stream().mapToDouble(Cheese::getPrice).su } }
  • 150. Let's get this conversation started

  • 151. public class Index extends WebPage { … public Index() { … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } }
  • 152. public class Index extends WebPage { … @Inject private Conversation shopping; public Index() { … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } }
  • 153. public class Index extends WebPage { … @Inject private Conversation shopping; public Index() { … shopping.begin(); … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } }
  • 154. public class Index extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart = new Cart(); public Index() { … shopping.begin(); … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } }
  • 155. public class Index extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public Index() { … shopping.begin(); … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage(cart)); } }); } }
  • 156. public class Index extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public Index() { … shopping.begin(); … add(new Link<Void>("checkout") { @Override public void onClick() { setResponsePage(new CheckoutPage()); } }); } }
  • 157. public class CheckoutPage extends WebPage { @EJB private OrderDao orders; private Order order = new Order(); private Cart cart; public CheckoutPage(Cart cart) { this.cart = cart; Form<Void> form = new Form<Void>("form") {…}; add(form); } }
  • 158. public class CheckoutPage extends WebPage { @EJB private OrderDao orders; private Order order = new Order(); private Cart cart; public CheckoutPage() { this.cart = cart; Form<Void> form = new Form<Void>("form") {…}; add(form); } }
  • 159. public class CheckoutPage extends WebPage { @EJB private OrderDao orders; private Order order = new Order(); private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") {…}; add(form); } }
  • 160. public class CheckoutPage extends WebPage { @EJB private OrderDao orders; private Order order = new Order(); @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") {…}; add(form); } }
  • 161. Let's end this conversation

  • 162. public class CheckoutPage extends WebPage { … @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") {…}; add(form); } }
  • 163. public class CheckoutPage extends WebPage { … @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) {…} orders.save(order); } }; add(form); } } end conversation here...
  • 164. public class CheckoutPage extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) {} orders.save(order); } }; add(form); } }
  • 165. public class CheckoutPage extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) {} orders.save(order); shopping.end(); } }; add(form); } }
  • 166.
  • 168.
  • 169. public class CheckoutPage extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) {} orders.save(order); shopping.end(); } }; add(form); } }
  • 170. public class CheckoutPage extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) {} orders.save(order); shopping.end(); } }; add(form); } }
  • 171. public class CheckoutPage extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) {} orders.save(order); shopping.end(); } }; add(form); } }
  • 172. public class CheckoutPage extends WebPage { … @Inject private Conversation shopping; @Inject private Cart cart; public CheckoutPage() { Form<Void> form = new Form<Void>("form") { @Override protected void onSubmit() { for (Cheese cheese : cart.getItems()) {} orders.save(order); shopping.end(); setResponsePage(Index.class); } }; add(form); }
  • 173. • Add wicket-cdi-1.1 and javax.cdi-api • Configure Wicket's CdiConfiguration • Use @Inject injection and @ConversationScoped • Use NonContextual in non-managed objects
  • 174. Injection (EJB, CDI) Conversations (CDI) JPA Bean validation Testing with Arquillian
  • 175. Cheese, Order, OrderItem now @Entity Order → OrderItem
 @OneToMany(fetchType=LAZY) OrderItem → Cheese, OrderItem → Order
 @ManyToOne(optional=false) CheeseDao, OrderDao now
 @Stateless
 @TransactionAttribute(REQUIRED)
  • 176. A refreshing model A model that reloads data from DB 
 for every render
  • 178. public class OrdersModel 
 extends LoadableDetachableModel<List<Order>> { }
  • 179. public class OrdersModel 
 extends LoadableDetachableModel<List<Order>> { @Override protected List<Order> load() { } }
  • 180. public class OrdersModel 
 extends LoadableDetachableModel<List<Order>> { @Override protected List<Order> load() { return orders.list(); } }
  • 181. public class OrdersModel 
 extends LoadableDetachableModel<List<Order>> { @Inject private OrderDao orders; @Override protected List<Order> load() { return orders.list(); } }
  • 182. public class OrdersModel 
 extends LoadableDetachableModel<List<Order>> { @Inject private OrderDao orders; public OrdersModel() { } @Override protected List<Order> load() { return orders.list(); } }
  • 183. public class OrdersModel 
 extends LoadableDetachableModel<List<Order>> { @Inject private OrderDao orders; public OrdersModel() { NonContextual.of(OrdersModel.class).inject(this); } @Override protected List<Order> load() { return orders.list(); } }
  • 184. public class OrdersPage extends WebPage { public OrdersPage() { add(new ListView<Order>("items", new OrdersModel()) { @Override protected void populateItem(ListItem<Order> item) { Order o = item.getModelObject(); item.add(new Label("id", o.getId())); item.add(new Label("name", o.getName())); item.add(new Label("total", o.getTotal())); } }); } }
  • 185. public class OrdersPage extends WebPage { public OrdersPage() { } }
  • 186. public class OrdersPage extends WebPage { public OrdersPage() { add(new ListView<Order>("items", new OrdersModel()) { }); } }
  • 187. public class OrdersPage extends WebPage { public OrdersPage() { add(new ListView<Order>("items", new OrdersModel()) { @Override protected void populateItem(ListItem<Order> item) { } }); } }
  • 188. public class OrdersPage extends WebPage { public OrdersPage() { add(new ListView<Order>("items", new OrdersModel()) { @Override protected void populateItem(ListItem<Order> item) { Order o = item.getModelObject(); item.add(new Label("id", o.getId())); item.add(new Label("name", o.getName())); item.add(new Label("total", o.getTotal())); } }); } }
  • 189.
  • 190. Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.cheesr.entities.Order.items, could not initialize proxy - no Session at org.hibernate.collection.internal.AbstractPersistentCollection.throw at org.hibernate.collection.internal.AbstractPersistentCollection.withT at org.hibernate.collection.internal.AbstractPersistentCollection.initi at org.hibernate.collection.internal.AbstractPersistentCollection.read( at org.hibernate.collection.internal.PersistentBag.iterator(PersistentB at java.util.Spliterators$IteratorSpliterator.estimateSize(Spliterators at java.util.Spliterator.getExactSizeIfKnown(Spliterator.java:408) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:511 at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.j at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.jav at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234 at java.util.stream.DoublePipeline.collect(DoublePipeline.java:476) at java.util.stream.DoublePipeline.sum(DoublePipeline.java:388) at com.cheesr.entities.Order.getTotal(Order.java:94) at com.cheesr.web.OrdersPage$1.populateItem(OrdersPage.java:22) at org.apache.wicket.markup.html.list.ListView.onPopulate(ListView.java at org.apache.wicket.markup.repeater.AbstractRepeater.onBeforeRender(Ab at org.apache.wicket.Component.internalBeforeRender(Component.java:949) at org.apache.wicket.Component.beforeRender(Component.java:1017) at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupConta ... 50 more
  • 191. LazyInitializationException failed to lazily initialize a collection of role: com.cheesr.entities.Order.items, could not initialize proxy - no Session
  • 192. LazyInitException: AARGH Why and how to get rid of them
  • 193. @Stateless @TransactionAttribute(TransactionAttributeType.REQUIRED) public class OrderDao implements Serializable { public void save(Order order) {…} public List<Order> list() {…} }
  • 194. @Stateless @TransactionAttribute(TransactionAttributeType.REQUIRED) public class OrderDao implements Serializable { public void save(Order order) {…} public List<Order> list() {…} }
  • 195. After dao.list() JPA session ends
  • 196. @Entity @Table(name = "Orders") public class Order implements Serializable { @Id @GeneratedValue private Long id; private String name; private String street; private String zipcode; private String city; private String country; @OneToMany(fetch = FetchType.LAZY, mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) private List<OrderItem> items = new ArrayList<>(); public Long getId() { return id;
  • 197. @Entity @Table(name = "Orders") public class Order implements Serializable { @Id @GeneratedValue private Long id; private String name; private String street; private String zipcode; private String city; private String country; @OneToMany(fetch = FetchType.LAZY, mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) private List<OrderItem> items = new ArrayList<>(); public Long getId() { return id;
  • 198. Generates lazy proxies, resolved upon request
  • 199. public class OrdersPage extends WebPage { public OrdersPage() { add(new ListView<Order>("items", new OrdersModel()) { @Override protected void populateItem(ListItem<Order> item) { Order o = item.getModelObject(); item.add(new Label("id", o.getId())); item.add(new Label("name", o.getName())); item.add(new Label("total", o.getTotal())); } }); } }
  • 200. public class OrdersPage extends WebPage { public OrdersPage() { add(new ListView<Order>("items", new OrdersModel()) { @Override protected void populateItem(ListItem<Order> item) { Order o = item.getModelObject(); item.add(new Label("id", o.getId())); item.add(new Label("name", o.getName())); item.add(new Label("total", o.getTotal())); } }); } }
  • 201. getTotal() requests upon the proxy: LazyInitException
  • 202. Fix LazyInitExceptions Extend transaction for whole request (using a Servlet 3.0 @WebFilter)
  • 203. @WebFilter(filterName = "Cheesr", value = "/*", initParams = { @WebInitParam( name = "applicationClassName", value = "com.cheesr.web.WicketApplication"), @WebInitParam( name = "filterMappingUrlPattern", value = "/*") }) public class CheesrFilter extends WicketFilter { @Override public void doFilter(ServletRequest req, ServletResponse super.doFilter(request, response, chain); } }
  • 204. @WebFilter(filterName = "Cheesr", value = "/*", initParams = { @WebInitParam( name = "applicationClassName", value = "com.cheesr.web.WicketApplication"), @WebInitParam( name = "filterMappingUrlPattern", value = "/*") }) public class CheesrFilter extends WicketFilter { @Transactional @Override public void doFilter(ServletRequest req, ServletResponse super.doFilter(request, response, chain); } }
  • 205.
  • 206. Rolling back a transaction
  • 207. When you use a reloading model
 e.g. CheeseLoadableModel And you use container managed transactions
 @Transactional WicketFilter Then be careful of unwanted modifications
  • 208. Form<Cheese> form = new Form<Cheese>("form", cheeseModel) { @Override protected void onSubmit() { Cheese cheese = getModelObject(); if (cheese.getPrice() < 1) { error("Price must be €1,- or higher"); } else { cheeseDao.save(cheese); setResponsePage(Index.class); } } }; add(form);
  • 209.
  • 210.
  • 211.
  • 212. "No news is good news..." – Container Managed Transactions
  • 213. Form<Cheese> form = new Form<Cheese>("form", cheeseModel) { @Override protected void onSubmit() { Cheese cheese = getModelObject(); if (cheese.getPrice() < 1) { error("Price must be €1,- or higher"); } else { cheeseDao.save(cheese); setResponsePage(Index.class); } } }; add(form);
  • 214. Form<Cheese> form = new Form<Cheese>("form", cheeseModel) { @Override protected void onSubmit() { Cheese cheese = getModelObject(); if (cheese.getPrice() < 1) { transactionBean.setTransactionRollbackOnly(); error("Price must be €1,- or higher"); } else { cheeseDao.save(cheese); setResponsePage(Index.class); } } }; add(form);
  • 215. @Stateless @TransactionAttribute(TransactionAttributeType.REQUIRED) public class TransactionBean { @Resource private SessionContext context; public void setTransactionRollbackOnly() { context.setRollbackOnly(); } }
  • 216. When you use a reloading model
 e.g. CheeseLoadableModel And you use container managed transactions
 @Transactional WicketFilter Then be careful of unwanted modifications
 and rollback the transaction
  • 217. Injection (EJB, CDI) Conversations (CDI) JPA Bean validation Testing with Arquillian
  • 218. Bean Validation Single Point of Definition
  • 219. Add dependencies Add validation constraints Configure Wicket Add Validators to components Steps
  • 220. <!-- BEAN VALIDATION DEPENDENCIES --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-bean-validation</artifactId> </dependency>
  • 221. @Entity @Table(name = "Orders") public class Order implements Serializable { @Id @GeneratedValue private Long id; private String name; private String street; private String zipcode; private String city; private String country; @OneToMany(fetch = FetchType.LAZY, mappedBy = "order", ca private List<OrderItem> items = new ArrayList<>();
  • 222. @Entity @Table(name = "Orders") public class Order implements Serializable { @Id @GeneratedValue private Long id; @NotNull private String name; private String street; private String zipcode; private String city; private String country; @OneToMany(fetch = FetchType.LAZY, mappedBy = "order", ca private List<OrderItem> items = new ArrayList<>();
  • 223. @Entity @Table(name = "Orders") public class Order implements Serializable { @Id @GeneratedValue private Long id; @NotNull private String name; @Size(min = 3, max = 20) @NotNull private String street; private String zipcode; private String city; private String country;
  • 224. @Entity @Table(name = "Orders") public class Order implements Serializable { @Id @GeneratedValue private Long id; @NotNull private String name; @Size(min = 3, max = 20) @NotNull private String street; @Pattern(regexp = "d{4} [A-Z]{2}") @NotNull private String zipcode; private String city;
  • 225. public void init() { super.init(); BeanValidationConfiguration beanValidation = new BeanValidationConfiguration(); beanValidation.configure(this); CdiConfiguration cdiConfiguration = new CdiConfiguration(); cdiConfiguration .setPropagation(ConversationPropagation.ALL); cdiConfiguration.configure(this); getComponentInstantiationListeners().add( new JavaEEComponentInjector(this, new WildflyWicketJndiNamingStrategy())); mountPage("/checkout", CheckoutPage.class); mountPage("/orders", OrdersPage.class); }
  • 226. TextField<String> nameField = new TextField<>("name", PropertyModel.of(this, "order.nam form.add(nameField); TextField<String> streetField = new TextField<>("street", PropertyModel.of(this, "order.s form.add(streetField);
  • 227. TextField<String> nameField = new TextField<>("name", PropertyModel.of(this, "order.nam nameField.add(new PropertyValidator<>()); form.add(nameField); TextField<String> streetField = new TextField<>("street", PropertyModel.of(this, "order.s form.add(streetField);
  • 228. TextField<String> nameField = new TextField<>("name", PropertyModel.of(this, "order.nam nameField.add(new PropertyValidator<>()); form.add(nameField); TextField<String> streetField = new TextField<>("street", PropertyModel.of(this, "order.s streetField.add(new PropertyValidator<>()); form.add(streetField);
  • 229. add wicket-bean-validation and javax.validation:validation-api to project configure BeanValidationConfiguration in init() add PropertyValidator to fields
  • 230. Injection (EJB, CDI) Conversations (CDI) JPA Bean validation Testing with Arquillian
  • 232. public class TestIndex { private WicketTester tester; @Before public void setUp() { WicketApplication app = new WicketApplication(); tester = new WicketTester(app); } @Test public void homepageRendersSuccessfully() { tester.startPage(Index.class); tester.assertRenderedPage(Index.class); } }
  • 233.
  • 234. • No bean manager • No data source • No persistence context • No transactions • No EJBs NO TESTS
  • 235. Arquillian No more mocks. No more container lifecycle and deployment hassles. Just real tests!
  • 236. Add Arquillian dependencies 
 to project Build deployable archive
 with all necessary resources Create a test case Execute test case with Arquillian Steps
  • 237. <!-- ARQUILLIAN DEPENDENCY FOR TESTING --> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency>
  • 238. <!-- ARQUILLIAN DEPENDENCY FOR TESTING --> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.shrinkwrap.descriptors</groupId> <artifactId>shrinkwrap-descriptors-impl-javaee</artifact <scope>test</scope> </dependency>
  • 239. <!-- ARQUILLIAN DEPENDENCY FOR TESTING --> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.shrinkwrap.descriptors</groupId> <artifactId>shrinkwrap-descriptors-impl-javaee</artifact <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.shrinkwrap.resolver</groupId> <artifactId>shrinkwrap-resolver-impl-maven</artifactId> <scope>test</scope> </dependency>
  • 240. Add Arquillian dependencies 
 to project Build deployable archive
 with all necessary resources Create a test case Execute test case with Arquillian Steps
  • 241. public class TestIndex { private WicketTester tester; @Before public void setUp() { WicketApplication app = new WicketApplication(); tester = new WicketTester(app); } @Test public void homepageRendersSuccessfully() { tester.startPage(Index.class); tester.assertRenderedPage(Index.class); } }
  • 242. @RunWith(Arquillian.class) public class TestIndex { private WicketTester tester; @Before public void setUp() { WicketApplication app = new WicketApplication(); tester = new WicketTester(app); } @Test public void homepageRendersSuccessfully() { tester.startPage(Index.class); tester.assertRenderedPage(Index.class); } }
  • 243. @RunWith(Arquillian.class) public class TestIndex { @Deployment public static WebArchive deployment() {…} private WicketTester tester; @Before public void setUp() { WicketApplication app = new WicketApplication(); tester = new WicketTester(app); } @Test public void homepageRendersSuccessfully() { tester.startPage(Index.class); tester.assertRenderedPage(Index.class); } }
  • 244. @Deployment public static WebArchive deployment() { File[] dependencies = Maven.configureResolver() .workOffline() .loadPomFromFile("pom.xml") .importCompileAndRuntimeDependencies() .resolve() .withTransitivity() .as(File.class); }
  • 245. @Deployment public static WebArchive deployment() { File[] dependencies = Maven.configureResolver() .workOffline() .loadPomFromFile("pom.xml") .importCompileAndRuntimeDependencies() .resolve() .withTransitivity() .as(File.class); WebArchive war = ShrinkWrap .create(WebArchive.class) .addAsResource(new File("target/classes"), "") .addAsLibraries(dependencies) .addAsWebInfResource( new File("src/main/webapp/WEB-INF/beans.xml")) .addAsWebInfResource( new File("src/main/webapp/WEB-INF/cheesr-ds.xml") return war; }
  • 246. 6ea1e1a7-7f07-4318-8f70-ec7b8d5edbcc.war: /WEB-INF/ /WEB-INF/lib/ /WEB-INF/lib/annotations-3.0.0.jar /WEB-INF/lib/wicketstuff-javaee-inject-6.17.0.jar /WEB-INF/lib/javax.inject-1.jar /WEB-INF/lib/wicket-cdi-1.1-6.18.0.jar /WEB-INF/lib/cglib-2.2.2.jar /WEB-INF/lib/fest-util-1.1.6.jar /WEB-INF/lib/wicket-ioc-6.18.0.jar /WEB-INF/lib/wicket-bean-validation-6.18.0.jar /WEB-INF/lib/wicket-request-6.18.0.jar /WEB-INF/lib/log4j-1.2.17.jar /WEB-INF/lib/asm-3.3.1.jar /WEB-INF/lib/fest-assert-1.4.jar /WEB-INF/lib/validation-api-1.1.0.Final.jar /WEB-INF/lib/slf4j-log4j12-1.7.7.jar /WEB-INF/lib/slf4j-api-1.7.7.jar /WEB-INF/lib/jcl-over-slf4j-1.7.7.jar /WEB-INF/lib/wicket-core-6.18.0.jar /WEB-INF/lib/wicket-util-6.18.0.jar /WEB-INF/cheesr-ds.xml /WEB-INF/classes/ /WEB-INF/classes/wildfly-doesnt-need-log4j.properties /WEB-INF/classes/META-INF/ /WEB-INF/classes/META-INF/persistence.xml /WEB-INF/classes/com/ /WEB-INF/classes/com/cheesr/ /WEB-INF/classes/com/cheesr/domain/ /WEB-INF/classes/com/cheesr/domain/Cart.class /WEB-INF/classes/com/cheesr/domain/MessageOfTheDay.class /WEB-INF/classes/com/cheesr/web/ /WEB-INF/classes/com/cheesr/web/CheckoutPage$2.class /WEB-INF/classes/com/cheesr/web/Index$2$1.class /WEB-INF/classes/com/cheesr/web/OrdersPage.class /WEB-INF/classes/com/cheesr/web/WicketApplication.class /WEB-INF/classes/com/cheesr/web/Index$1$1.class /WEB-INF/classes/com/cheesr/web/Index.html /WEB-INF/classes/com/cheesr/web/WicketApplication$WildflyWicketJndiNamingStrategy.class /WEB-INF/classes/com/cheesr/web/Index$2.class /WEB-INF/classes/com/cheesr/web/CheckoutPage.class /WEB-INF/classes/com/cheesr/web/CheckoutPage.html /WEB-INF/classes/com/cheesr/web/Index.class /WEB-INF/classes/com/cheesr/web/CheesrFilter.class /WEB-INF/classes/com/cheesr/web/MessageModel.class /WEB-INF/classes/com/cheesr/web/Index$3.class /WEB-INF/classes/com/cheesr/web/OrdersModel.class
  • 247. Add Arquillian dependencies 
 to project Build deployable archive
 with all necessary resources Create a test case Execute test case with Arquillian Steps
  • 248.
  • 249. Add Arquillian dependencies 
 to project Build deployable archive
 with all necessary resources Create a test case Execute test case with Arquillian Steps
  • 250. @Inject private Conversation conversation; @EJB private CheeseDao cheeses; @Inject private Cart cart; @Test public void addCheeseToCart() { }
  • 252. public void addCheeseToCart() { Cheese edam = cheeses.byCode("edam"); }
  • 253. public void addCheeseToCart() { Cheese edam = cheeses.byCode("edam"); tester.startPage(Index.class); tester.assertRenderedPage(Index.class); }
  • 254. public void addCheeseToCart() { Cheese edam = cheeses.byCode("edam"); tester.startPage(Index.class); tester.assertRenderedPage(Index.class); tester.assertModelValue("cheese:1", edam); }
  • 255. public void addCheeseToCart() { Cheese edam = cheeses.byCode("edam"); tester.startPage(Index.class); tester.assertRenderedPage(Index.class); tester.assertModelValue("cheese:1", edam); tester.clickLink("cheese:1:add"); assertThat(cart.getItems().size(), is(1)); tester.assertModelValue("item:0", edam); }
  • 256. public void addCheeseToCart() { Cheese edam = cheeses.byCode("edam"); tester.startPage(Index.class); tester.assertRenderedPage(Index.class); tester.assertModelValue("cheese:1", edam); tester.clickLink("cheese:1:add"); assertThat(cart.getItems().size(), is(1)); tester.assertModelValue("item:0", edam); tester.clickLink("cheese:1:add"); assertThat(cart.getItems().size(), is(2)); assertThat(cart.getItems().get(0), is(edam)); assertThat(cart.getItems().get(1), is(edam)); }
  • 257. public void addCheeseToCart() { Cheese edam = cheeses.byCode("edam"); tester.startPage(Index.class); tester.assertRenderedPage(Index.class); tester.assertModelValue("cheese:1", edam); tester.clickLink("cheese:1:add"); assertThat(cart.getItems().size(), is(1)); tester.assertModelValue("item:0", edam); tester.clickLink("cheese:1:add"); assertThat(cart.getItems().size(), is(2)); assertThat(cart.getItems().get(0), is(edam)); assertThat(cart.getItems().get(1), is(edam)); tester.clickLink("checkout"); tester.assertRenderedPage(CheckoutPage.class); }
  • 258.
  • 259. with Arquillian you can test Wicket pages with JPA, CDI, EJB add Arquillian dependencies to POM, add arquillian.xml for container connection create a deployment write and run your tests
  • 260. Injection (EJB, CDI) Conversations (CDI) JPA Bean validation Arquillian
  • 262.