SlideShare a Scribd company logo
Introducing
Apache Wicket
Martijn Dashorst
Agenda


•   Introduction to Apache Wicket
•   New and noteworthy in 1.5
•   Questions
Martijn Dashorst

•   Employee @ Topicus
•   Chair for Apache Wicket
•   Committer
•   Apache Member
•   Author Wicket in Action
Introduction
Wicket is...
a component oriented web framework
using just HTML and Java
Apache Wicket

•   Open Source: ASL 2.0
•   Created in 2004
•   Java web framework
•   Component oriented
•   http://wicket.apache.org
Who’s using Wicket?
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
Wicket 2010
mobile.walmart.com supports three categories
of devices using the same Java code (only the html
is (very) different.)

Try doing that with JSP.
           — Joachim Kainz
... We at Vegas.com have been able to re-
purpose our Wicket-based air/hotel search
application and purchase/checkout application.
This is the new mexico.com. [...]

The re-use of components and abstract pages
was tremendous.

      —Scott Swank, chief architect vegas.com
Just HTML
Sign up form




Example from Railscast episode #250
Sign up form
Sign up form
  <h1>Sign Up</h1>

  <form>
   <div class="error_messages">
    <h2>Form is invalid</h2>
    <ul>
     <li>Some error message</li>
    </ul>
   </div>
   <p>
    <label for="email">E-Mail</label><br/>
    <input type="email" id="email" />
   </p>
   <p>
    <label for="password">Password</label>
    <input type="password" id="password" />
   </p>
   <p>
    <label for="confirm">Password confirmat
    <input type="password" id="confirm" />
   </p>
   <p class="button"><input type="submit" va
Sign up form
Sign up form
  <h1>Sign Up</h1>  
    
  <%= form_for @user do |f| %>  
    <% if @user.errors.any? %>  
      <div class="error_messages">  
        <h2>Form is invalid</h2>  
        <ul>  
          <% for message in @user.errors.full  
            <li><%= message %></li>  
          <% end %>  
        </ul>  
      </div>  
    <% end %>  
    <p>  
      <%= f.label :email %><br />  
      <%= f.text_field :email %>  
    </p>  
    <p>  
      <%= f.label :password %><br />  
      <%= f.password_field :password %>  
    </p>  
    <p>
Sign up form
  <h1>Sign Up</h1>

  <form>
   <div class="error_messages">
    <h2>Form is invalid</h2>
    <ul>
     <li>Some error message</li>
    </ul>
   </div>
   <p>
    <label for="email">E-Mail</label><br/>
    <input type="email" id="email" />
   </p>
   <p>
    <label for="password">Password</label>
    <input type="password" id="password" />
   </p>
   <p>
    <label for="confirm">Password confirmat
    <input type="password" id="confirm" />
   </p>
   <p class="button"><input type="submit" va
Sign up form
  <h1>Sign Up</h1>

  <form>
   <div wicket:id="feedback" class="error_me
    <h2>Form is invalid</h2>
    <ul>
     <li>Some error message</li>
    </ul>
   </div>
   <p>
    <label for="email">E-Mail</label><br/>
    <input wicket:id="email" type="email" i
   </p>
   <p>
    <label for="password">Password</label>
    <input wicket:id="password" type="passw
   </p>
   <p>
    <label for="confirm">Password confirmat
    <input wicket:id="confirm" type="passwo
   </p>
   <p class="button"><input type="submit" va
Sign up form
  <h1>Sign Up</h1>

  <form>
   <div wicket:id="feedback" class="error_me
    <h2>Form is invalid</h2>
    <ul>
     <li>Some error message</li>
    </ul>
   </div>
   <p>
    <label for="email">E-Mail</label><br/>
    <input wicket:id="email" type="email" i
   </p>
   <p>
    <label for="password">Password</label>
    <input wicket:id="password" type="passw
   </p>
   <p>
    <label for="confirm">Password confirmat
    <input wicket:id="confirm" type="passwo
   </p>
   <p class="button"><input type="submit" va
<tag wicket:id="foo">
Instructs Wicket to work on this tag
Imperative markup
                               <h1>Sign Up</h1>

•   Used by Ruby on Rails,     <%= form_for @user do |f| %>
                                 <% if @user.errors.any? %>
    JSP, Play, Velocity, ...       <div class="error_messag
                                     <h2>Form is invalid</h

•
                                     <ul>
    Great for web developers           <% for message in @u
                                         <li><%= message %>
•   Great for hacking on a             <% end %>
                                     </ul>
    web site                       </div>
                                 <% end %>
                                 <p>
•   Code and markup are            <%= f.label :email %><br
                                   <%= f.text_field :email 
    not separated                </p>
                                 <p>
Declarative markup
                                <h1>Sign Up</h1>

•   Used by Wicket, Tapestry,   <form wicket:id="form">
                                 <div class="error_message
    Facelets                     <p>
                                  <label for="email">E-Ma

•   Great for web designers
                                  <input type="email" id=
                                 </p>
                                 <p>
•   Go from PSD → HTML →          <label for="password">P
                                  <input type="password"
    Page → Component             </p>
                                 <p>
                                  <label for="confirm">Pa
•   Code and markup are           <input type="password"
                                 </p>
    strictly separated           <p class="button"><input
                                </form>
Just Java
Sign up form
<h1>Sign Up</h1>  
  
<%= form_for @user do |f| %>  
  <% if @user.errors.any? %>  
    <div class="error_messages">  
      <h2>Form is invalid</h2>  
      <ul>  
        <% for message in @user.errors.full_messages %>  
          <li><%= message %></li>  
        <% end %>  
      </ul>  
    </div>  
  <% end %>  
  <p>  
    <%= f.label :email %><br />  
    <%= f.text_field :email %>  
  </p>  
  <p>  
    <%= f.label :password %><br />  
    <%= f.password_field :password %>  
  </p>  
  <p>  
    <%= f.label :password_confirmation %>  
Sign up form
Form form = new Form("signup") {
  @Override
  public void onSubmit() {
     // ...
  }
}
add(form);
Sign up form
Form form = new Form("signup") {
  @Override
  public void onSubmit() {
     // ...
  }
}
add(form);

FeedbackPanel feedback = new FeedbackPanel("feedback");
feedback.setVisible(form.hasFeedbackMessages());
form.add(feedback);
Sign up form
Form form = new Form("signup") {
  @Override
  public void onSubmit() {
     // ...
  }
}
add(form);

FeedbackPanel feedback = new FeedbackPanel("feedback");
feedback.setVisible(form.hasFeedbackMessages());
form.add(feedback);

form.add(new EmailTextField("email", Model.of(""))
         .setRequired(true));
Sign up form
Form form = new Form("signup") {
  @Override
  public void onSubmit() {
     // ...
  }
}
add(form);

FeedbackPanel feedback = new FeedbackPanel("feedback");
feedback.setVisible(form.hasFeedbackMessages());
form.add(feedback);

form.add(new EmailTextField("email", Model.of(""))
         .setRequired(true));

form.add(new PasswordField("password", Model.of(""))
         .setRequired(true));
Sign up form
Form form = new Form("signup") {
  @Override
  public void onSubmit() {
     // ...
  }
}
add(form);

FeedbackPanel feedback = new FeedbackPanel("feedback");
feedback.setVisible(form.hasFeedbackMessages());
form.add(feedback);

form.add(new EmailTextField("email", Model.of(""))
         .setRequired(true));

form.add(new PasswordField("password", Model.of(""))
         .setRequired(true));

form.add(new PasswordField("confirm", Model.of(""))
         .setRequired(true));
Just Java

•   No logic in markup
•   Components are objects (use new and extends)
•   Use OO techniques in your programming
•   No XML
Concepts
Components
•   Manipulate markup
•   Render content
•   Receive events (onClick, onSubmit)


•   Examples:
    Label, Link, Form, TextField, PagingNavigator, Panel,
    Page, ClientSideImageMap
Models

•   Provide data to components
•   Store data for components
•   Transform data
•   Retrieve data from persistent storage


•   Examples: Model<T>, PropertyModel<T>
Behaviors

•   Decorator/Adapter for Component
•   Can manipulate markup of Component
•   Can receive events (onClick)
•   Add Ajax functionality to components
•   Example: AjaxSelfUpdatingTimerBehavior
Getting started
Wicket projects
•   Apache Wicket                                •   Leg before Wicket
    (extensions, spring, guice, velocity, etc)       (Maven archetypes)


•   Wicket stuff                                 •   Apache Isis
    (grand collection of projects)                   (incubating, DDD framework)


•   Seam for Apache                              •   Jolira Tools
    Wicket                                           (powers mobile.walmart.com)


•   WiQuery                                      •   Visural Wicket
                                                     (standalone Wicket components)
    (JQuery integration library)
Apache Wicket projects
•   Core          •   Velocity
•   Extensions    •   Auth/Roles
•   Quick start   •   JMX
•   IoC           •   Dev utils
    •   Spring
    •   Guice     •   Examples

•   DateTime
Wicket Stuff projects
•   progressbar              •   shiro-security                 •   theme

•   datatable-autocomplete   •   gae-initializer                •   yav

•   flot                      •   push-jdk-1.5                   •   maven-support

•   googlecharts             •   jasperreports                  •   plugin

•   scala-extensions         •   mbeanview                      •   input-events

•   openlayers               •   jsr303                         •   javaee-inject

•   gmap2                    •   client-and-server-validation   •   push

•   inmethod-grid            •   multi-text-input               •   wicket-html5

•   minis                    •   prototype                      •   wicket-servlet3

•   phonebook                •   simile-timeline
Quick start
Quick start
Running quickstart
$_
Running quickstart
$ mvn -o archetype:generate -DarchetypeGroupId=org.apache.wicket -
DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.5-
SNAPSHOT -DgroupId=com.mycompany -DartifactId=myproject -
DarchetypeRepository=https://repository.apache.org/content/repositories/
snapshots/ -DinteractiveMode=false _
Running quickstart
$ mvn -o archetype:generate -DarchetypeGroupId=org.apache.wicket -
DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.5-
SNAPSHOT -DgroupId=com.mycompany -DartifactId=myproject -
DarchetypeRepository=https://repository.apache.org/content/repositories/
snapshots/ -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO] -----------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] -----------------------------------------------------------
[INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) >>>
[INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) <<<
[INFO] --- maven-archetype-plugin:2.0:generate (default-cli) ---
[INFO] Generating project in Batch mode
[INFO] Archetype defined by properties
[INFO] -----------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------
[INFO] Total time: 1.279s
[INFO] Finished at: Fri Feb 04 22:04:14 CET 2011
[INFO] Final Memory: 9M/81M
[INFO] -----------------------------------------------------------
Running quickstart
$ mvn jetty:run_
Running quickstart
$ mvn jetty:run
[INFO] Scanning for projects...
[INFO] -----------------------------------------------------------
[INFO] Building quickstart 1.0-SNAPSHOT
[INFO] -----------------------------------------------------------
[INFO] Starting jetty 7.2.2.v20101205 ...
2011-02-04 22:04:34.969:INFO::jetty-7.2.2.v20101205
2011-02-04 22:04:35.198:INFO::No Transaction manager found - if yo
INFO - WebXmlFile               - web.xml: found filter with na
INFO - Application             - [wicket.myproject] init: Wick
INFO - RequestListenerInterface - registered listener interface
INFO - WebApplication             - [wicket.myproject] Started Wi
******************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.               ***
***                      ^^^^^^^^^^^               ***
*** Do NOT deploy to your live server(s) without changing this.***
*** See Application#getConfigurationType() for more information***
******************************************************************
2011-02-04 22:04:35.464:INFO::Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
Running quickstart
Quick start alternative
           Leg up
           •   Spring
           •   Guice
           •   JDBC
           •   JPA
           •   Hibernate
           •   Scala

           http://jweekend.com/dev/LegUp
Want to learn more?
Want to learn more?
Want to learn more?

http://wicket.apache.org/learn/books.html
Examples
Examples
Hello, World!
Hello, World!
<h1>Hello, World</h1>
Hello, World!
<h1>[Replaced text]</h1>
Hello, World!
<h1 wicket:id="msg">[Replaced text]</h1>
Hello, World!
<h1 wicket:id="msg">[Replaced text]</h1>

                   +

 add(new Label("msg", "Hello, World!"));
Hello, World!
<h1 wicket:id="msg">[Replaced text]</h1>

                    +

  add(new Label("msg", "Hello, World!"));

                    =

        <h1>Hello, World!</h1>
Examples
Click counter
This link has been clicked 123 times
This link has been clicked 123 times

This link has been clicked 123 times!
This link has been clicked 123 times

This <a href="#">link</a> has been clicked 123
times!
This link has been clicked 123 times

This <a href="#">link</a> has been clicked
<span>123</span> times!
This link has been clicked 123 times

This <a wicket:id="link" href="#">link</a> has been
clicked <span>123</span> times!
This link has been clicked 123 times

This <a wicket:id="link" href="#">link</a> has been
clicked
<span wicket:id="clicks">123</span> times!
This link has been clicked 123 times

This <a wicket:id="link" href="#">link</a> has been
clicked
<span wicket:id="clicks">123</span> times!
This link has been clicked 123 times

public class ClickCountPage extends WebPage {
}
This link has been clicked 123 times

public class ClickCountPage extends WebPage {
  public ClickCountPage() {
  }
}
This link has been clicked 123 times

public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCountPage() {
    }
}
This link has been clicked 123 times

public class ClickCountPage extends WebPage {
 private int clicks = 0;

 public ClickCountPage() {
   add(new Link<Void>("link") {
      public void onClick() {
        clicks++;
      }
    });
 }
This link has been clicked 123 times

public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCountPage() {
      add(new Link<Void>("link") { ... });
      add(new Label("clicks",
          new PropertyModel<Integer>(this,
                "clicks")));
    }
}
Wicket for developers
2 modes for your app
Development and Deployment
Development mode
$ mvn jetty:run
[INFO] Scanning for projects...
[INFO] -----------------------------------------------------------
[INFO] Building quickstart 1.0-SNAPSHOT
[INFO] -----------------------------------------------------------
[INFO] Starting jetty 7.2.2.v20101205 ...
2011-02-04 22:04:34.969:INFO::jetty-7.2.2.v20101205
2011-02-04 22:04:35.198:INFO::No Transaction manager found - if yo
INFO - WebXmlFile               - web.xml: found filter with na
INFO - Application             - [wicket.myproject] init: Wick
INFO - RequestListenerInterface - registered listener interface
INFO - WebApplication             - [wicket.myproject] Started Wi
******************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.               **
***                      ^^^^^^^^^^^               **
*** Do NOT deploy to your live server(s) without changing this. **
*** See Application#getConfigurationType() for more information **
******************************************************************
2011-02-04 22:04:35.464:INFO::Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
Development mode
•   exceptional error pages
•   dynamic markup reloading
•   no caching
•   no javascript/css optimizations
•   discover mistakes early (serialization, missing
    components, ...)
•   Wicket debugger visible
Deployment mode

•   Cache markup resources
•   No checks
•   Don’t display stack traces to users
•   Minimize/compress JavaScript
•   Don’t generate wicket tags
•   Wicket debugger not visible
FREE PRO TIP:

Don’t perform your performance tests
in development mode!
Ajax debugger
Ajax debugger
Ajax envelope
<?xml version="1.0" encoding="UTF-8"?>
<ajax-response>
 <component id="count2">
  <![CDATA[<span wicket:id="count" id="count2">1</span>]]>
 </component>
</ajax-response>
Error message
Unable to find component with id 'count'
in HomePage.
This means that you declared
wicket:id=count in your markup, but that
you either did not add the component to
your page at all, or that the hierarchy does
not match.
Error pages
Testing the UI
WicketTester

•   Test components directly, or their markup
•   Runs tests without starting server
•   Ajax testing (server side)
•   Runs in IDE, ant, maven builds
•   Achieves high code coverage
Testing Hello, World!
@Test
public void rendersWelcomeMessage() {
}
Testing Hello, World!
@Test
public void rendersWelcomeMessage() {
  WicketTester tester = new WicketTester();
}
Testing Hello, World!
@Test
public void rendersWelcomeMessage() {
  WicketTester tester = new WicketTester();
  tester.startPage(HelloWorldPage.class);
}
Testing Hello, World!
@Test
public void rendersWelcomeMessage() {
  WicketTester tester = new WicketTester();
  tester.startPage(HelloWorldPage.class);
  tester.assertLabel("msg", "Hello, World!");
}
Testing Click Count
@Test
public void clicksIncreaseCount() {
}
Testing Click Count
@Test
public void clicksIncreaseCount() {
  WicketTester tester = new WicketTester();
}
Testing Click Count
@Test
public void clicksIncreaseCount() {
  WicketTester tester = new WicketTester();
  tester.startPage(ClickCountPage.class);
}
Testing Click Count
@Test
public void clicksIncreaseCount() {
  WicketTester tester = new WicketTester();
  tester.startPage(ClickCountPage.class);
  tester.assertModelValue("clicks", 0);
}
Testing Click Count
@Test
public void clicksIncreaseCount() {
  WicketTester tester = new WicketTester();
  tester.startPage(ClickCountPage.class);
  tester.assertModelValue("clicks", 0);
  tester.clickLink("link");
}
Testing Click Count
@Test
public void clicksIncreaseCount() {
  WicketTester tester = new WicketTester();
  tester.startPage(ClickCountPage.class);
  tester.assertModelValue("clicks", 0);
  tester.clickLink("link");
  tester.assertModelValue("clicks", 1);
}
Other test frameworks


•   PageTest (by Kent Tong)
•   JDave (BDD framework)
Summary

•   Widely used
•   Component oriented
•   Java
•   Open Source (ASL 2.0)
What’s new in 1.5?
HTML 5 support
Pre 1.5


•   Checks for valid markup don’t accept new field types
•   HTML 5 defines:
    <input type=”text|email|password|number|date|
    search|url|...”>
Wicket 1.5

•   EmailTextField
•   NumberTextField
•   UrlTextField
•   RangeTextField
Improved internals
Split up core library
•   Old:
    •   wicket.jar
Split up core library
•   Old:
    •   wicket.jar
•   New:
    •   wicket-requests.jar
    •   wicket-util.jar
    •   wicket-core.jar
Maven users
<dependency>
  <groupId>org.apache.wicket</groupId>
  <artifactId>wicket-core</artifactId>
  <version>1.5-RC1</version>
</dependency>
Simpler request cycle
Wicket < 1.5

•   Decoding request and handling in state machine
•   Debugging ‘interesting’
•   Designed for flexibility
•   Served its purpose—took on 4 years of engineering
Wicket 1.5


•   Request cycle processing completely rewritten
•   Rendering code has been improved and simplified
•   URL rendering simplified: now in one place
Wicket < 1.5

•   Custom request cycle: subclass WebRequestCycle
•   Problematic with add-ons:
    •   HibernateRequestCycle
    •   SecureRequestCycle
    •   ActivityRequestCycle
New: RequestCycleListener
public interface IRequestCycleListener {

    void onBeginRequest(RequestCycle cycle);

    void onEndRequest(RequestCycle cycle);

    void onDetach(RequestCycle cycle);

    IRequestHandler onException(RequestCycle cycle, Exception ex);
}
RequestCycleListener
public class SomeWebApplication extends WebApplication {
  @Override
  protected void init() {
  }

    @Override
    public Class<? extends Page> getHomePage() {
      return SomePage.class;
    }
}
RequestCycleListener
public class SomeWebApplication extends WebApplication {
  @Override
  protected void init() {
     addRequestCycleListener(new IRequestCycleListener() {
        public void onBeginRequest() {
           // do something at the beginning of the request
        }

              public void onEndRequest() {
                // do something at the end of the request
              }

              public void onException(Exception ex) {
                // do something here when there's an exception
              }
        });
    }

    @Override
    public Class<? extends Page> getHomePage() {
      return SomePage.class;
    }
}
Switching to HTTPS
Switching to HTTPS
public SecurePage extends WebPage {
  ...
}

public MyApplications extends WebApplication {
 @Override
 public void init() {
  super.init();

    }
}
Switching to HTTPS
@RequireHttps
public SecurePage extends WebPage {
  ...
}

public MyApplications extends WebApplication {
 @Override
 public void init() {
  super.init();

    }
}
Switching to HTTPS
@RequireHttps
public SecurePage extends WebPage {
  ...
}

public MyApplications extends WebApplication {
  @Override
  public void init() {
    super.init();
    setRootRequestMapper(
      new HttpsMapper(getRootRequestMapper(),
                  new HttpsConfig());
  }
}
Component event bus
Component event bus

•   IEventSource: objects that send events
    <T> void send(IEventSink sink,
                      Broadcast broadcast, T payload);
•   IEventSink: objects that receive events
    void onEvent(IEvent<?> event);
•   Participants: Components, RequestCycle, Session and
    Application
Event bus example
Ajax link counter
This link has been clicked 123 times
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new Link<Void>("link") {
          @Override
          public void onClick() {
            count++;
          }
        });
      add(new Label("clicks",
               new PropertyModel<Integer>(this, "clicks")));
    }
}
This link has been clicked 123 times
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new Link<Void>("link") {
          @Override
          public void onClick() {
            count++;
          }
        });
      add(new Label("clicks",
                new PropertyModel<Integer>(this, "clicks"))
            .setOutputMarkupId(true));
    }
}
This link has been clicked 123 times
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") {
          @Override
          public void onClick(AjaxRequestTarget target) {
            count++;
          }
        });
      add(new Label("clicks",
                new PropertyModel<Integer>(this, "clicks"))
            .setOutputMarkupId(true));
    }
}
This link has been clicked 123 times
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") {
          @Override
          public void onClick(AjaxRequestTarget target) {
            count++;
             target.add(getPage().get("count"));
          }
        });
      add(new Label("count",
                new PropertyModel<Integer>(this, "clicks"))
            .setOutputMarkupId(true));
    }
}
This link has been clicked 123 times
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") {
          @Override
          public void onClick(AjaxRequestTarget target) {
            count++;
            target.add(getPage().get("count"));
          }
        });
      add(new Label("count",
                new PropertyModel<Integer>(this, "clicks"))
            .setOutputMarkupId(true));
    }
}
Pre-event bus

•   Link needs to know the updatable components
•   Makes code brittle, hard to maintain


•   Better:
    •   Let the label refresh itself with each Ajax request
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") {
          @Override
          public void onClick(AjaxRequestTarget target) {
            count++;
             target.add(getPage().get("count"));
          }
        });
      add(new Label("count",
                new PropertyModel<Integer>(this, "clicks"))
            .setOutputMarkupId(true));
    }
}
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") {
          @Override
          public void onClick(AjaxRequestTarget target) {
            count++;
             send(getPage(), Broadcast.BREADTH, target);
          }
        });
      add(new Label("count",
                new PropertyModel<Integer>(this, "clicks"))
            .setOutputMarkupId(true));
    }
}
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") {
          @Override
          public void onClick(AjaxRequestTarget target) {
            count++;
            send(getPage(), Broadcast.BREADTH, target);
          }
        });
      add(new CountLabel("count", new PropertyModel<Integer>(this,
    }
}
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") { ... });
      add(new CountLabel("count", new PropertyModel<Integer>(this,
    }

    public class CountLabel extends Label {
    }
}
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") { ... });
      add(new CountLabel("count", new PropertyModel<Integer>(this,
    }

    public class CountLabel extends Label {
      public CountLabel(String id, IModel<Integer> model) {
        super(id, model);
      }
    }
}
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") { ... });
      add(new CountLabel("count", new PropertyModel<Integer>(this,
    }

    public class CountLabel extends Label {
      public CountLabel(String id, IModel<Integer> model) {
        super(id, model);
        setOutputMarkupId(true);
      }
    }
}
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") { ... });
      add(new CountLabel("count", new PropertyModel<Integer>(this,
    }

    public class CountLabel extends Label {
     public CountLabel(String id, IModel<Integer> model) {
       super(id, model);
       setOutputMarkupId(true);
     }

        @Override
        public void onEvent(IEvent<?> event) {
          super.onEvent(event);
        }
    }
}
public class ClickCountPage extends WebPage {
 private int clicks = 0;

    public ClickCount() {
      add(new AjaxLink<Void>("link") { ... });
      add(new CountLabel("count", new PropertyModel<Integer>(this,
    }

    public class CountLabel extends Label {
     public CountLabel(String id, IModel<Integer> model) {
       super(id, model);
       setOutputMarkupId(true);
     }

        @Override
        public void onEvent(IEvent<?> event) {
         super.onEvent(event);

            if (event.getPayload() instanceof AjaxRequestTarget) {
              AjaxRequestTarget target =
                          (AjaxRequestTarget) event.getPayload();
              target.add(this);
            }
        }
    }
}
Post-event bus

•   A bit more code
•   Updates are now completely decoupled
•   Make the payload type safe and meaningful:
    no AjaxRequestTarget, but CountEvent
•   AJAX requests trigger a default event with an
    AjaxRequestTarget as payload
And much, much more:
http://cwiki.apache.org/WICKET/
migration-to-wicket15.html
Thank you!
    Questions? Ask!

More Related Content

PDF
Apache Wicket Web Framework
ODP
Wicket Next (1.4/1.5)
PDF
Integrating Plone with E-Commerce and Relationship Management: A Case Study i...
PDF
Building an HTML5 Video Player
PDF
Intro to html 5
PDF
HTML5 & CSS3 refresher for mobile apps
PDF
HTML5 and CSS3 refresher
PDF
webcomponents (Jfokus 2015)
Apache Wicket Web Framework
Wicket Next (1.4/1.5)
Integrating Plone with E-Commerce and Relationship Management: A Case Study i...
Building an HTML5 Video Player
Intro to html 5
HTML5 & CSS3 refresher for mobile apps
HTML5 and CSS3 refresher
webcomponents (Jfokus 2015)

What's hot (20)

PDF
HTML5 and the dawn of rich mobile web applications
PDF
Keypoints html5
PDF
Local storage in Web apps
PDF
DirectToWeb 2.0
PDF
Backbone JS for mobile apps
PDF
Usability in the GeoWeb
PDF
Basics of css and xhtml
PDF
Web Standards: Fueling Innovation [Web Design World Boston '08]
PDF
Rails for Mobile Devices @ Conferencia Rails 2011
PDF
Rails + Webpack
PDF
Web Components & Polymer 1.0 (Webinale Berlin)
PDF
[FEConf Korea 2017]Angular 컴포넌트 대화법
PPTX
Why Django for Web Development
PDF
HTML5 and the dawn of rich mobile web applications pt 1
PDF
Introduction to HTML5
PPT
High Performance Ajax Applications
KEY
Templates
KEY
Mobile HTML, CSS, and JavaScript
PDF
Week 05 Web, App and Javascript_Brandon, S.H. Wu
PDF
jQuery UI and Plugins
HTML5 and the dawn of rich mobile web applications
Keypoints html5
Local storage in Web apps
DirectToWeb 2.0
Backbone JS for mobile apps
Usability in the GeoWeb
Basics of css and xhtml
Web Standards: Fueling Innovation [Web Design World Boston '08]
Rails for Mobile Devices @ Conferencia Rails 2011
Rails + Webpack
Web Components & Polymer 1.0 (Webinale Berlin)
[FEConf Korea 2017]Angular 컴포넌트 대화법
Why Django for Web Development
HTML5 and the dawn of rich mobile web applications pt 1
Introduction to HTML5
High Performance Ajax Applications
Templates
Mobile HTML, CSS, and JavaScript
Week 05 Web, App and Javascript_Brandon, S.H. Wu
jQuery UI and Plugins
Ad

Viewers also liked (10)

PPT
Wicket体験談
PPTX
Project Lombok!
KEY
Integrating Wicket with Java EE 6
PDF
Lombok ハンズオン
PDF
Lombokのススメ
PDF
The State of Wicket
PDF
Wicket Presentation @ AlphaCSP Java Web Frameworks Playoff 2008
PDF
Apache Wicket: Web Applications With Just Java
PPTX
GDC Europe 2014: Unreal Engine 4 for Programmers - Lessons Learned & Things t...
PPT
Wicket Introduction
Wicket体験談
Project Lombok!
Integrating Wicket with Java EE 6
Lombok ハンズオン
Lombokのススメ
The State of Wicket
Wicket Presentation @ AlphaCSP Java Web Frameworks Playoff 2008
Apache Wicket: Web Applications With Just Java
GDC Europe 2014: Unreal Engine 4 for Programmers - Lessons Learned & Things t...
Wicket Introduction
Ad

Similar to Wicket 2010 (20)

PDF
Mobile themes, QR codes, and shortURLs
PDF
Action View Form Helpers - 1, Season 2
PDF
TechDays 2013 Jari Kallonen: What's New WebForms 4.5
DOC
QuickConnect
PDF
GitBucket: The perfect Github clone by Scala
PDF
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
PDF
GDG Addis - An Introduction to Django and App Engine
KEY
PHPConf-TW 2012 # Twig
PPTX
SPTechCon Dev Days - Third Party jQuery Libraries
PDF
HTML5 Refresher
PPTX
Utilizing jQuery in SharePoint: Get More Done Faster
PDF
django_introduction20141030
PPTX
Semantic UI Introduction
PDF
Web Components for Java Developers
PPTX
Polytechnic speaker deck oluwadamilare
PPTX
Polytechnic speaker deck oluwadamilare
PPTX
`From Prototype to Drupal` by Andrew Ivasiv
PPTX
SPTechCon DevDays - SharePoint & jQuery
PDF
Introduction to web components
PPTX
SPTechCon Boston 2015 - Utilizing jQuery in SharePoint
Mobile themes, QR codes, and shortURLs
Action View Form Helpers - 1, Season 2
TechDays 2013 Jari Kallonen: What's New WebForms 4.5
QuickConnect
GitBucket: The perfect Github clone by Scala
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
GDG Addis - An Introduction to Django and App Engine
PHPConf-TW 2012 # Twig
SPTechCon Dev Days - Third Party jQuery Libraries
HTML5 Refresher
Utilizing jQuery in SharePoint: Get More Done Faster
django_introduction20141030
Semantic UI Introduction
Web Components for Java Developers
Polytechnic speaker deck oluwadamilare
Polytechnic speaker deck oluwadamilare
`From Prototype to Drupal` by Andrew Ivasiv
SPTechCon DevDays - SharePoint & jQuery
Introduction to web components
SPTechCon Boston 2015 - Utilizing jQuery in SharePoint

More from Martijn Dashorst (20)

PDF
HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0
PDF
From Floppy Disks to Cloud Deployments
PDF
SOLID principles
PDF
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
PDF
Solutions for when documentation fails
PDF
Whats up with wicket 8 and java 8
PDF
Code review drinking game
PDF
Java Serialization Deep Dive
PDF
Code review drinking game
PDF
Scrum: van praktijk naar onderwijs
PDF
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
PDF
De schone coder
PDF
Wicket 10 years and beyond
PDF
Apache Wicket and Java EE sitting in a tree
PDF
Vakmanschap is meesterschap
PDF
Keep your Wicket application in production
PDF
Wicket In Action - oredev2008
PDF
Guide To Successful Graduation at Apache
PDF
Wicket In Action
PDF
Wicket Live on Stage
HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0
From Floppy Disks to Cloud Deployments
SOLID principles
Converting 85% of Dutch Primary Schools from Oracle to PostgreSQL
Solutions for when documentation fails
Whats up with wicket 8 and java 8
Code review drinking game
Java Serialization Deep Dive
Code review drinking game
Scrum: van praktijk naar onderwijs
Who Automates the Automators? (Quis Automatiet Ipsos Automates?)
De schone coder
Wicket 10 years and beyond
Apache Wicket and Java EE sitting in a tree
Vakmanschap is meesterschap
Keep your Wicket application in production
Wicket In Action - oredev2008
Guide To Successful Graduation at Apache
Wicket In Action
Wicket Live on Stage

Recently uploaded (20)

PPTX
1. Introduction to Computer Programming.pptx
PPT
Module 1.ppt Iot fundamentals and Architecture
PPTX
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
PDF
NewMind AI Weekly Chronicles – August ’25 Week III
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PPT
What is a Computer? Input Devices /output devices
PDF
Web App vs Mobile App What Should You Build First.pdf
PDF
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
PPTX
TLE Review Electricity (Electricity).pptx
PPTX
The various Industrial Revolutions .pptx
PDF
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
PDF
TrustArc Webinar - Click, Consent, Trust: Winning the Privacy Game
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
PPTX
Tartificialntelligence_presentation.pptx
PPTX
Final SEM Unit 1 for mit wpu at pune .pptx
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PPTX
Modernising the Digital Integration Hub
PDF
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
1. Introduction to Computer Programming.pptx
Module 1.ppt Iot fundamentals and Architecture
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
NewMind AI Weekly Chronicles – August ’25 Week III
NewMind AI Weekly Chronicles - August'25-Week II
What is a Computer? Input Devices /output devices
Web App vs Mobile App What Should You Build First.pdf
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
TLE Review Electricity (Electricity).pptx
The various Industrial Revolutions .pptx
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
TrustArc Webinar - Click, Consent, Trust: Winning the Privacy Game
Univ-Connecticut-ChatGPT-Presentaion.pdf
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
Tartificialntelligence_presentation.pptx
Final SEM Unit 1 for mit wpu at pune .pptx
Group 1 Presentation -Planning and Decision Making .pptx
Modernising the Digital Integration Hub
Transform Your ITIL® 4 & ITSM Strategy with AI in 2025.pdf
Profit Center Accounting in SAP S/4HANA, S4F28 Col11

Wicket 2010

  • 2. Agenda • Introduction to Apache Wicket • New and noteworthy in 1.5 • Questions
  • 3. Martijn Dashorst • Employee @ Topicus • Chair for Apache Wicket • Committer • Apache Member • Author Wicket in Action
  • 5. Wicket is... a component oriented web framework using just HTML and Java
  • 6. Apache Wicket • Open Source: ASL 2.0 • Created in 2004 • Java web framework • Component oriented • http://wicket.apache.org
  • 25. mobile.walmart.com supports three categories of devices using the same Java code (only the html is (very) different.) Try doing that with JSP. — Joachim Kainz
  • 26. ... We at Vegas.com have been able to re- purpose our Wicket-based air/hotel search application and purchase/checkout application. This is the new mexico.com. [...] The re-use of components and abstract pages was tremendous. —Scott Swank, chief architect vegas.com
  • 28. Sign up form Example from Railscast episode #250
  • 30. Sign up form <h1>Sign Up</h1> <form> <div class="error_messages"> <h2>Form is invalid</h2> <ul> <li>Some error message</li> </ul> </div> <p> <label for="email">E-Mail</label><br/> <input type="email" id="email" /> </p> <p> <label for="password">Password</label> <input type="password" id="password" /> </p> <p> <label for="confirm">Password confirmat <input type="password" id="confirm" /> </p> <p class="button"><input type="submit" va
  • 32. Sign up form <h1>Sign Up</h1>      <%= form_for @user do |f| %>     <% if @user.errors.any? %>       <div class="error_messages">         <h2>Form is invalid</h2>         <ul>           <% for message in @user.errors.full             <li><%= message %></li>           <% end %>         </ul>       </div>     <% end %>     <p>       <%= f.label :email %><br />       <%= f.text_field :email %>     </p>     <p>       <%= f.label :password %><br />       <%= f.password_field :password %>     </p>     <p>
  • 33. Sign up form <h1>Sign Up</h1> <form> <div class="error_messages"> <h2>Form is invalid</h2> <ul> <li>Some error message</li> </ul> </div> <p> <label for="email">E-Mail</label><br/> <input type="email" id="email" /> </p> <p> <label for="password">Password</label> <input type="password" id="password" /> </p> <p> <label for="confirm">Password confirmat <input type="password" id="confirm" /> </p> <p class="button"><input type="submit" va
  • 34. Sign up form <h1>Sign Up</h1> <form> <div wicket:id="feedback" class="error_me <h2>Form is invalid</h2> <ul> <li>Some error message</li> </ul> </div> <p> <label for="email">E-Mail</label><br/> <input wicket:id="email" type="email" i </p> <p> <label for="password">Password</label> <input wicket:id="password" type="passw </p> <p> <label for="confirm">Password confirmat <input wicket:id="confirm" type="passwo </p> <p class="button"><input type="submit" va
  • 35. Sign up form <h1>Sign Up</h1> <form> <div wicket:id="feedback" class="error_me <h2>Form is invalid</h2> <ul> <li>Some error message</li> </ul> </div> <p> <label for="email">E-Mail</label><br/> <input wicket:id="email" type="email" i </p> <p> <label for="password">Password</label> <input wicket:id="password" type="passw </p> <p> <label for="confirm">Password confirmat <input wicket:id="confirm" type="passwo </p> <p class="button"><input type="submit" va
  • 37. Imperative markup <h1>Sign Up</h1> • Used by Ruby on Rails, <%= form_for @user do |f| %>   <% if @user.errors.any? %> JSP, Play, Velocity, ...     <div class="error_messag       <h2>Form is invalid</h •       <ul> Great for web developers         <% for message in @u           <li><%= message %> • Great for hacking on a         <% end %>       </ul> web site     </div>   <% end %>   <p> • Code and markup are     <%= f.label :email %><br     <%= f.text_field :email  not separated   </p>   <p>
  • 38. Declarative markup <h1>Sign Up</h1> • Used by Wicket, Tapestry, <form wicket:id="form"> <div class="error_message Facelets <p> <label for="email">E-Ma • Great for web designers <input type="email" id= </p> <p> • Go from PSD → HTML → <label for="password">P <input type="password" Page → Component </p> <p> <label for="confirm">Pa • Code and markup are <input type="password" </p> strictly separated <p class="button"><input </form>
  • 41. Sign up form Form form = new Form("signup") { @Override public void onSubmit() { // ... } } add(form);
  • 42. Sign up form Form form = new Form("signup") { @Override public void onSubmit() { // ... } } add(form); FeedbackPanel feedback = new FeedbackPanel("feedback"); feedback.setVisible(form.hasFeedbackMessages()); form.add(feedback);
  • 43. Sign up form Form form = new Form("signup") { @Override public void onSubmit() { // ... } } add(form); FeedbackPanel feedback = new FeedbackPanel("feedback"); feedback.setVisible(form.hasFeedbackMessages()); form.add(feedback); form.add(new EmailTextField("email", Model.of("")) .setRequired(true));
  • 44. Sign up form Form form = new Form("signup") { @Override public void onSubmit() { // ... } } add(form); FeedbackPanel feedback = new FeedbackPanel("feedback"); feedback.setVisible(form.hasFeedbackMessages()); form.add(feedback); form.add(new EmailTextField("email", Model.of("")) .setRequired(true)); form.add(new PasswordField("password", Model.of("")) .setRequired(true));
  • 45. Sign up form Form form = new Form("signup") { @Override public void onSubmit() { // ... } } add(form); FeedbackPanel feedback = new FeedbackPanel("feedback"); feedback.setVisible(form.hasFeedbackMessages()); form.add(feedback); form.add(new EmailTextField("email", Model.of("")) .setRequired(true)); form.add(new PasswordField("password", Model.of("")) .setRequired(true)); form.add(new PasswordField("confirm", Model.of("")) .setRequired(true));
  • 46. Just Java • No logic in markup • Components are objects (use new and extends) • Use OO techniques in your programming • No XML
  • 48. Components • Manipulate markup • Render content • Receive events (onClick, onSubmit) • Examples: Label, Link, Form, TextField, PagingNavigator, Panel, Page, ClientSideImageMap
  • 49. Models • Provide data to components • Store data for components • Transform data • Retrieve data from persistent storage • Examples: Model<T>, PropertyModel<T>
  • 50. Behaviors • Decorator/Adapter for Component • Can manipulate markup of Component • Can receive events (onClick) • Add Ajax functionality to components • Example: AjaxSelfUpdatingTimerBehavior
  • 52. Wicket projects • Apache Wicket • Leg before Wicket (extensions, spring, guice, velocity, etc) (Maven archetypes) • Wicket stuff • Apache Isis (grand collection of projects) (incubating, DDD framework) • Seam for Apache • Jolira Tools Wicket (powers mobile.walmart.com) • WiQuery • Visural Wicket (standalone Wicket components) (JQuery integration library)
  • 53. Apache Wicket projects • Core • Velocity • Extensions • Auth/Roles • Quick start • JMX • IoC • Dev utils • Spring • Guice • Examples • DateTime
  • 54. Wicket Stuff projects • progressbar • shiro-security • theme • datatable-autocomplete • gae-initializer • yav • flot • push-jdk-1.5 • maven-support • googlecharts • jasperreports • plugin • scala-extensions • mbeanview • input-events • openlayers • jsr303 • javaee-inject • gmap2 • client-and-server-validation • push • inmethod-grid • multi-text-input • wicket-html5 • minis • prototype • wicket-servlet3 • phonebook • simile-timeline
  • 58. Running quickstart $ mvn -o archetype:generate -DarchetypeGroupId=org.apache.wicket - DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.5- SNAPSHOT -DgroupId=com.mycompany -DartifactId=myproject - DarchetypeRepository=https://repository.apache.org/content/repositories/ snapshots/ -DinteractiveMode=false _
  • 59. Running quickstart $ mvn -o archetype:generate -DarchetypeGroupId=org.apache.wicket - DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.5- SNAPSHOT -DgroupId=com.mycompany -DartifactId=myproject - DarchetypeRepository=https://repository.apache.org/content/repositories/ snapshots/ -DinteractiveMode=false [INFO] Scanning for projects... [INFO] ----------------------------------------------------------- [INFO] Building Maven Stub Project (No POM) 1 [INFO] ----------------------------------------------------------- [INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) >>> [INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) <<< [INFO] --- maven-archetype-plugin:2.0:generate (default-cli) --- [INFO] Generating project in Batch mode [INFO] Archetype defined by properties [INFO] ----------------------------------------------------------- [INFO] BUILD SUCCESS [INFO] ----------------------------------------------------------- [INFO] Total time: 1.279s [INFO] Finished at: Fri Feb 04 22:04:14 CET 2011 [INFO] Final Memory: 9M/81M [INFO] -----------------------------------------------------------
  • 61. Running quickstart $ mvn jetty:run [INFO] Scanning for projects... [INFO] ----------------------------------------------------------- [INFO] Building quickstart 1.0-SNAPSHOT [INFO] ----------------------------------------------------------- [INFO] Starting jetty 7.2.2.v20101205 ... 2011-02-04 22:04:34.969:INFO::jetty-7.2.2.v20101205 2011-02-04 22:04:35.198:INFO::No Transaction manager found - if yo INFO - WebXmlFile - web.xml: found filter with na INFO - Application - [wicket.myproject] init: Wick INFO - RequestListenerInterface - registered listener interface INFO - WebApplication - [wicket.myproject] Started Wi ****************************************************************** *** WARNING: Wicket is running in DEVELOPMENT mode. *** *** ^^^^^^^^^^^ *** *** Do NOT deploy to your live server(s) without changing this.*** *** See Application#getConfigurationType() for more information*** ****************************************************************** 2011-02-04 22:04:35.464:INFO::Started SelectChannelConnector@0.0.0.0:8080 [INFO] Started Jetty Server
  • 63. Quick start alternative Leg up • Spring • Guice • JDBC • JPA • Hibernate • Scala http://jweekend.com/dev/LegUp
  • 64. Want to learn more?
  • 65. Want to learn more?
  • 66. Want to learn more? http://wicket.apache.org/learn/books.html
  • 72. Hello, World! <h1 wicket:id="msg">[Replaced text]</h1> + add(new Label("msg", "Hello, World!"));
  • 73. Hello, World! <h1 wicket:id="msg">[Replaced text]</h1> + add(new Label("msg", "Hello, World!")); = <h1>Hello, World!</h1>
  • 75. This link has been clicked 123 times
  • 76. This link has been clicked 123 times This link has been clicked 123 times!
  • 77. This link has been clicked 123 times This <a href="#">link</a> has been clicked 123 times!
  • 78. This link has been clicked 123 times This <a href="#">link</a> has been clicked <span>123</span> times!
  • 79. This link has been clicked 123 times This <a wicket:id="link" href="#">link</a> has been clicked <span>123</span> times!
  • 80. This link has been clicked 123 times This <a wicket:id="link" href="#">link</a> has been clicked <span wicket:id="clicks">123</span> times!
  • 81. This link has been clicked 123 times This <a wicket:id="link" href="#">link</a> has been clicked <span wicket:id="clicks">123</span> times!
  • 82. This link has been clicked 123 times public class ClickCountPage extends WebPage { }
  • 83. This link has been clicked 123 times public class ClickCountPage extends WebPage { public ClickCountPage() { } }
  • 84. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCountPage() { } }
  • 85. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCountPage() { add(new Link<Void>("link") { public void onClick() { clicks++; } }); }
  • 86. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCountPage() { add(new Link<Void>("link") { ... }); add(new Label("clicks", new PropertyModel<Integer>(this, "clicks"))); } }
  • 88. 2 modes for your app Development and Deployment
  • 89. Development mode $ mvn jetty:run [INFO] Scanning for projects... [INFO] ----------------------------------------------------------- [INFO] Building quickstart 1.0-SNAPSHOT [INFO] ----------------------------------------------------------- [INFO] Starting jetty 7.2.2.v20101205 ... 2011-02-04 22:04:34.969:INFO::jetty-7.2.2.v20101205 2011-02-04 22:04:35.198:INFO::No Transaction manager found - if yo INFO - WebXmlFile - web.xml: found filter with na INFO - Application - [wicket.myproject] init: Wick INFO - RequestListenerInterface - registered listener interface INFO - WebApplication - [wicket.myproject] Started Wi ****************************************************************** *** WARNING: Wicket is running in DEVELOPMENT mode. ** *** ^^^^^^^^^^^ ** *** Do NOT deploy to your live server(s) without changing this. ** *** See Application#getConfigurationType() for more information ** ****************************************************************** 2011-02-04 22:04:35.464:INFO::Started SelectChannelConnector@0.0.0.0:8080 [INFO] Started Jetty Server
  • 90. Development mode • exceptional error pages • dynamic markup reloading • no caching • no javascript/css optimizations • discover mistakes early (serialization, missing components, ...) • Wicket debugger visible
  • 91. Deployment mode • Cache markup resources • No checks • Don’t display stack traces to users • Minimize/compress JavaScript • Don’t generate wicket tags • Wicket debugger not visible
  • 92. FREE PRO TIP: Don’t perform your performance tests in development mode!
  • 95. Ajax envelope <?xml version="1.0" encoding="UTF-8"?> <ajax-response> <component id="count2"> <![CDATA[<span wicket:id="count" id="count2">1</span>]]> </component> </ajax-response>
  • 96. Error message Unable to find component with id 'count' in HomePage. This means that you declared wicket:id=count in your markup, but that you either did not add the component to your page at all, or that the hierarchy does not match.
  • 99. WicketTester • Test components directly, or their markup • Runs tests without starting server • Ajax testing (server side) • Runs in IDE, ant, maven builds • Achieves high code coverage
  • 100. Testing Hello, World! @Test public void rendersWelcomeMessage() { }
  • 101. Testing Hello, World! @Test public void rendersWelcomeMessage() { WicketTester tester = new WicketTester(); }
  • 102. Testing Hello, World! @Test public void rendersWelcomeMessage() { WicketTester tester = new WicketTester(); tester.startPage(HelloWorldPage.class); }
  • 103. Testing Hello, World! @Test public void rendersWelcomeMessage() { WicketTester tester = new WicketTester(); tester.startPage(HelloWorldPage.class); tester.assertLabel("msg", "Hello, World!"); }
  • 104. Testing Click Count @Test public void clicksIncreaseCount() { }
  • 105. Testing Click Count @Test public void clicksIncreaseCount() { WicketTester tester = new WicketTester(); }
  • 106. Testing Click Count @Test public void clicksIncreaseCount() { WicketTester tester = new WicketTester(); tester.startPage(ClickCountPage.class); }
  • 107. Testing Click Count @Test public void clicksIncreaseCount() { WicketTester tester = new WicketTester(); tester.startPage(ClickCountPage.class); tester.assertModelValue("clicks", 0); }
  • 108. Testing Click Count @Test public void clicksIncreaseCount() { WicketTester tester = new WicketTester(); tester.startPage(ClickCountPage.class); tester.assertModelValue("clicks", 0); tester.clickLink("link"); }
  • 109. Testing Click Count @Test public void clicksIncreaseCount() { WicketTester tester = new WicketTester(); tester.startPage(ClickCountPage.class); tester.assertModelValue("clicks", 0); tester.clickLink("link"); tester.assertModelValue("clicks", 1); }
  • 110. Other test frameworks • PageTest (by Kent Tong) • JDave (BDD framework)
  • 111. Summary • Widely used • Component oriented • Java • Open Source (ASL 2.0)
  • 114. Pre 1.5 • Checks for valid markup don’t accept new field types • HTML 5 defines: <input type=”text|email|password|number|date| search|url|...”>
  • 115. Wicket 1.5 • EmailTextField • NumberTextField • UrlTextField • RangeTextField
  • 117. Split up core library • Old: • wicket.jar
  • 118. Split up core library • Old: • wicket.jar • New: • wicket-requests.jar • wicket-util.jar • wicket-core.jar
  • 119. Maven users <dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-core</artifactId> <version>1.5-RC1</version> </dependency>
  • 121. Wicket < 1.5 • Decoding request and handling in state machine • Debugging ‘interesting’ • Designed for flexibility • Served its purpose—took on 4 years of engineering
  • 122. Wicket 1.5 • Request cycle processing completely rewritten • Rendering code has been improved and simplified • URL rendering simplified: now in one place
  • 123. Wicket < 1.5 • Custom request cycle: subclass WebRequestCycle • Problematic with add-ons: • HibernateRequestCycle • SecureRequestCycle • ActivityRequestCycle
  • 124. New: RequestCycleListener public interface IRequestCycleListener { void onBeginRequest(RequestCycle cycle); void onEndRequest(RequestCycle cycle); void onDetach(RequestCycle cycle); IRequestHandler onException(RequestCycle cycle, Exception ex); }
  • 125. RequestCycleListener public class SomeWebApplication extends WebApplication { @Override protected void init() { } @Override public Class<? extends Page> getHomePage() { return SomePage.class; } }
  • 126. RequestCycleListener public class SomeWebApplication extends WebApplication { @Override protected void init() { addRequestCycleListener(new IRequestCycleListener() { public void onBeginRequest() { // do something at the beginning of the request } public void onEndRequest() { // do something at the end of the request } public void onException(Exception ex) { // do something here when there's an exception } }); } @Override public Class<? extends Page> getHomePage() { return SomePage.class; } }
  • 128. Switching to HTTPS public SecurePage extends WebPage { ... } public MyApplications extends WebApplication { @Override public void init() { super.init(); } }
  • 129. Switching to HTTPS @RequireHttps public SecurePage extends WebPage { ... } public MyApplications extends WebApplication { @Override public void init() { super.init(); } }
  • 130. Switching to HTTPS @RequireHttps public SecurePage extends WebPage { ... } public MyApplications extends WebApplication { @Override public void init() { super.init(); setRootRequestMapper( new HttpsMapper(getRootRequestMapper(), new HttpsConfig()); } }
  • 132. Component event bus • IEventSource: objects that send events <T> void send(IEventSink sink, Broadcast broadcast, T payload); • IEventSink: objects that receive events void onEvent(IEvent<?> event); • Participants: Components, RequestCycle, Session and Application
  • 133. Event bus example Ajax link counter
  • 134. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new Link<Void>("link") { @Override public void onClick() { count++; } }); add(new Label("clicks", new PropertyModel<Integer>(this, "clicks"))); } }
  • 135. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new Link<Void>("link") { @Override public void onClick() { count++; } }); add(new Label("clicks", new PropertyModel<Integer>(this, "clicks")) .setOutputMarkupId(true)); } }
  • 136. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { count++; } }); add(new Label("clicks", new PropertyModel<Integer>(this, "clicks")) .setOutputMarkupId(true)); } }
  • 137. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { count++; target.add(getPage().get("count")); } }); add(new Label("count", new PropertyModel<Integer>(this, "clicks")) .setOutputMarkupId(true)); } }
  • 138. This link has been clicked 123 times public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { count++; target.add(getPage().get("count")); } }); add(new Label("count", new PropertyModel<Integer>(this, "clicks")) .setOutputMarkupId(true)); } }
  • 139. Pre-event bus • Link needs to know the updatable components • Makes code brittle, hard to maintain • Better: • Let the label refresh itself with each Ajax request
  • 140. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { count++; target.add(getPage().get("count")); } }); add(new Label("count", new PropertyModel<Integer>(this, "clicks")) .setOutputMarkupId(true)); } }
  • 141. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { count++; send(getPage(), Broadcast.BREADTH, target); } }); add(new Label("count", new PropertyModel<Integer>(this, "clicks")) .setOutputMarkupId(true)); } }
  • 142. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { count++; send(getPage(), Broadcast.BREADTH, target); } }); add(new CountLabel("count", new PropertyModel<Integer>(this, } }
  • 143. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { ... }); add(new CountLabel("count", new PropertyModel<Integer>(this, } public class CountLabel extends Label { } }
  • 144. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { ... }); add(new CountLabel("count", new PropertyModel<Integer>(this, } public class CountLabel extends Label { public CountLabel(String id, IModel<Integer> model) { super(id, model); } } }
  • 145. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { ... }); add(new CountLabel("count", new PropertyModel<Integer>(this, } public class CountLabel extends Label { public CountLabel(String id, IModel<Integer> model) { super(id, model); setOutputMarkupId(true); } } }
  • 146. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { ... }); add(new CountLabel("count", new PropertyModel<Integer>(this, } public class CountLabel extends Label { public CountLabel(String id, IModel<Integer> model) { super(id, model); setOutputMarkupId(true); } @Override public void onEvent(IEvent<?> event) { super.onEvent(event); } } }
  • 147. public class ClickCountPage extends WebPage { private int clicks = 0; public ClickCount() { add(new AjaxLink<Void>("link") { ... }); add(new CountLabel("count", new PropertyModel<Integer>(this, } public class CountLabel extends Label { public CountLabel(String id, IModel<Integer> model) { super(id, model); setOutputMarkupId(true); } @Override public void onEvent(IEvent<?> event) { super.onEvent(event); if (event.getPayload() instanceof AjaxRequestTarget) { AjaxRequestTarget target = (AjaxRequestTarget) event.getPayload(); target.add(this); } } } }
  • 148. Post-event bus • A bit more code • Updates are now completely decoupled • Make the payload type safe and meaningful: no AjaxRequestTarget, but CountEvent • AJAX requests trigger a default event with an AjaxRequestTarget as payload
  • 149. And much, much more: http://cwiki.apache.org/WICKET/ migration-to-wicket15.html
  • 150. Thank you! Questions? Ask!

Editor's Notes