http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/forms2/forms2_5.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/forms2/forms2_5.adoc b/wicket-user-guide/src/main/asciidoc/forms2/forms2_5.adoc new file mode 100644 index 0000000..4d65fd2 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/forms2/forms2_5.adoc @@ -0,0 +1,130 @@ + + + +Besides submitting forms with a standard HTML submit button, Wicket allows us to use special components which implement interface IFormSubmittingComponent. This entity is a subinterface of IFormSubmitter: + +image::../img/class-diag-IFormSubmittingComponent.png[] + +At the beginning of this chapter we have seen that form processing is started by process method which takes as input an instance of IFormSubmitter. This parameter corresponds to the IFormSubmittingComponent clicked by a user to submit the form and it is null if we have used a standard HTML submit button (like we have done so far). + +A submitting component is added to a form just like any other child component using method add(Component...). + +A form can have any number of submitting components and we can specify which one among them is the default one by calling the Form's method setDefaultButton(IFormSubmittingComponent  component). The default submitter is the one that will be used when user presses 'Enter' key in a field of the form. In order to make the default button work, Wicket will add to our form a hidden <div> tag containing a text field and a submit button with some JavaScript code to trigger it: + +[source,html] +---- +<div style="width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden"> + <input type="text" autocomplete="off"/> + <input type="submit" name="submit2" onclick=" var b=document...."/> +</div> +---- + +Just like Wicket forms, interface IFormSubmitter defines methods onSubmit and onError. These two methods have the priority over the namesake methods of the form, meaning that when a form is submitted with an IFormSubmitter, the onSubmit of the submitter is called before the one of the form. Similarly, if validation errors occurs during the first step of form processing, submitter's method onError is called before the form's one. + +NOTE: Starting with Wicket version 6.0 interface IFormSubmitter defines a further callback method called onAfterSubmit(). This method is called after form's method onSubmit() has been executed. + +=== Components Button and SubmitLink + +Component _org.apache.wicket.markup.html.form.Button_ is a basic implementation of a form submitter. It can be used with either the <input> or <button> tags. The string model received as input by its constructor is used as button label and it will be the value of the markup attribute value. + +In the following snippet we have a form with two submit buttons bound to an <input> tag. One of them is set as default button and both have a string model for the label: + +*HTML:* + +[source,html] +---- +<body> + <form wicket:id="form"> + Username: <input type="text" wicket:id="username"/> + <br/> + <input type="submit" wicket:id="submit1"/> + <input type="submit" wicket:id="submit2"/> + </form> +</body> +---- + +*Java code:* + +[source,java] +---- +public class HomePage extends WebPage { + + public HomePage(final PageParameters parameters) { + Form form = new Form("form"); + + form.add(new TextField("username", Model.of(""))); + form.add(new Button("submit1", Model.of("First submitter"))); + Button secondSubmitter; + form.add(secondSubmitter = new Button("submit2", Model.of("Second submitter"))); + + form.setDefaultButton(secondSubmitter); + add(form); + } +} +---- + +*Generated markup:* + +[source,html] +---- +<form wicket:id="form" id="form1" method="post" action="?0-1.IFormSubmitListener-form"> + <div> + ... + <!-- Code generated by Wicket to handle the default button --> + ... + </div> + Username: <input type="text" wicket:id="username" value="" name="username"/> + <br/> + <input type="submit" wicket:id="submit1" name="submit1" id="submit13" value="First submitter"/> + <input type="submit" wicket:id="submit2" name="submit2" id="submit22" value="Second submitter"/> +</form> +---- + +Another component that can be used to submit a form is _org.apache.wicket.markup.html.form.SubmitLink_. This component uses JavaScript to submit the form. Like the name suggests, the component can be used with the <a> tag but it can be also bound to any other tag that supports the event handler onclick. When used with the <a> tag, the JavaScript code needed to submit the form will be placed inside href attribute while with other tags the script will go inside the event handler onclick. + +A notable difference between this component and Button is that SubmitLink can be placed outside the form it must submit. In this case we must specify the form to submit in its constructor: + +*HTML:* + +[source,html] +---- +<html xmlns:wicket="http://wicket.apache.org"> + <head> + </head> + <body> + <form wicket:id="form"> + Password: <input type="password" wicket:id="password"/> + <br/> + </form> + <button wicket:id="externalSubmitter"> + Submit + </button> + </body> +</html> +---- + +*Java code:* + +[source,java] +---- +public class HomePage extends WebPage { + + public HomePage(final PageParameters parameters) { + Form form = new Form("form"); + + form.add(new PasswordTextField("password", Model.of(""))); + //specify the form to submit + add(new SubmitLink("externalSubmitter", form)); + add(form); + } +} +---- + +=== Disabling default form processing + +With an IFormSubmittingComponent we can choose to skip the default form submission process by setting the appropriate flag to false with the setDefaultFormProcessing method. When the default form processing is disabled only the submitter's onSubmit is called while form's validation and models updating are skipped. + +This can be useful if we want to implement a âCancelâ button on our form which redirects user to another page without validating his/her input. + +When we set this flag to false we can decide to manually invoke the form processing by calling the process(IFormSubmittingComponent) method. +
http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/forms2/forms2_6.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/forms2/forms2_6.adoc b/wicket-user-guide/src/main/asciidoc/forms2/forms2_6.adoc new file mode 100644 index 0000000..7d36664 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/forms2/forms2_6.adoc @@ -0,0 +1,24 @@ + + + +As you might already known, HTLM doesn't allow to have nested forms. However with Wicket we can overcome this limitation by adding one or more form components to a parent form. + +This can be useful if we want to split a big form into smaller ones in order to reuse them and to better distribute responsibilities among different components. +Forms can be nested to an arbitrary level: + +[source,html] +---- +<form wicket:id="outerForm"> + ... + <form wicket:id="innerForm"> + ... + <form wicket:id="veryInnerForm"> + ... + </form> + </form> +</form> +---- + +When a form is submitted also its nested forms are submitted and they participate in the validation step. This means that if a nested form contains invalid input values, the outer form won't be submitted. On the contrary, nested forms can be singularly submitted without depending on the status of their outer form. + +To submit a parent form when one of its children forms is submitted, we must override its method wantSubmitOnNestedFormSubmit and make it return true. http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/forms2/forms2_7.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/forms2/forms2_7.adoc b/wicket-user-guide/src/main/asciidoc/forms2/forms2_7.adoc new file mode 100644 index 0000000..3caa433 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/forms2/forms2_7.adoc @@ -0,0 +1,20 @@ + + + +HTML provides a multi-line text input control with <textarea> tag. The Wicket counterpart for this kind of control is _org.apache.wicket.markup.html.form.TextArea_ component: + +*HTML:* + +[source,html] +---- +<textarea wicket:id="description" rows="5" cols="40"></textarea> +---- + +*Java code:* + +[source,java] +---- +form.add(new TextArea("description", Model.of(""))); +---- + +Component TextArea is used just like any other single-line text field. To specify the size of the text area we can write attributes rows and cols directly in the markup file or we can create new attribute modifiers and add them to our TextArea component. http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/forms2/forms2_8.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/forms2/forms2_8.adoc b/wicket-user-guide/src/main/asciidoc/forms2/forms2_8.adoc new file mode 100644 index 0000000..5c7be68 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/forms2/forms2_8.adoc @@ -0,0 +1,84 @@ + + + +Wicket supports file uploading with the FileUploadField component which must be used with the <input> tag whose type attribute must be set to [file] In order to send a file on form submission we must enable multipart mode calling MultiPart(true)on our form. + +In the next example (project UploadSingleFile) we will see a form which allows users to upload a file into the temporary directory of the server (path /tmp on Unix/Linux systems): + +*HTML:* + +[source,html] +---- +<html> + <head> + </head> + <body> + <h1>Upload your file here!</h1> + <form wicket:id="form"> + <input type="file" wicket:id="fileUploadField"/> + <input type="submit" value="Upload"/> + </form> + <div wicket:id="feedbackPanel"> + </div> + </body> +</html> +---- + +*Java code:* + +[source,java] +---- +public class HomePage extends WebPage { + private FileUploadField fileUploadField; + + public HomePage(final PageParameters parameters) { + fileUploadField = new FileUploadField("fileUploadField"); + + Form form = new Form("form"){ + @Override + protected void onSubmit() { + super.onSubmit(); + + FileUpload fileUpload = fileUploadField.getFileUpload(); + + try { + File file = new File(System.getProperty("java.io.tmpdir") + "/" + + fileUpload.getClientFileName()); + + fileUpload.writeTo(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + }; + + form.setMultiPart(true); + //set a limit for uploaded file's size + form.setMaxSize(Bytes.kilobytes(100)); + form.add(fileUploadField); + add(new FeedbackPanel("feedbackPanel")); + add(form); + } +} +---- + +The code that copies the uploaded file to the temporary directory is inside the onSubmit method of the Form class. The uploaded file is handled with an instance of class FileUpload returned by the getFileUpload() method of the FileUploadField class. This class provides a set of methods to perform some common tasks like getting the name of the uploaded file (getClientFileName()), coping the file into a directory (writeTo(destinationFile)), calculating file digest (getDigest (digestAlgorithm)) and so on. + +Form component can limit the size for uploaded files using its setMaxSize(size) method. In the example we have set this limit to 100 kb to prevent users from uploading files bigger than this size. + +NOTE: The maximum size for uploaded files can also be set at application's level using the setDefaultMaximumUploadSize(Bytes maxSize) method of class ApplicationSettings: + +[source,java] +---- +@Override +public void init() +{ + getApplicationSettings().setDefaultMaximumUploadSize(Bytes.kilobytes(100)); +} +---- + +=== Upload multiple files + +If we need to upload multiple files at once and our clients support HTML5, we can still use FileUploadField adding attribute [multiple] to its tag. If we can not rely on HTML5, we can use the MultiFileUploadField component which allows the user to upload an arbitrary number of files using a JavaScript-based solution. +An example showing how to use this component can be found in Wicket module wicket-examples in file MultiUploadPage.java. The live example is hosted at {externalink:wicket.examples.url_upload/multi} . + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/forms2/forms2_9.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/forms2/forms2_9.adoc b/wicket-user-guide/src/main/asciidoc/forms2/forms2_9.adoc new file mode 100644 index 0000000..6722442 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/forms2/forms2_9.adoc @@ -0,0 +1,128 @@ + + + +In <<layout.adoc#_here_comes_the_inheritance,chapter 5.2.2>> we have seen how to use class Panel to create custom components with their own markup and with an arbitrary number of children components. + +While it's perfectly legal to use Panel also to group form components, the resulting component won't be itself a form component and it won't participate in the form's submission workflow. + +This could be a strong limitation if the custom component needs to coordinate its children during sub-tasks like input conversion or model updating. That's why in Wicket we have the _org.apache.wicket.markup.html.form.FormComponentPanel_ component which combines the features of a Panel (it has its own markup file) and a FormComponent (it is a subclass of FormComponent). + +A typical scenario in which we may need to implement a custom FormComponentPanel is when our web application and its users work with different units of measurement for the same data. + +To illustrate this possible scenario, let's consider a form where a user can insert a temperature that will be recorded after being converted to Kelvin degrees (see the example project CustomForm ComponentPanel). + +The Kelvin scale is wildly adopted among the scientific community and it is one of the seven base units of the http://en.wikipedia.org/wiki/International_System_of_Units[International System of Units] , so it makes perfect sense to store temperatures expressed with this unit of measurement. + +However, in our everyday life we still use other temperature scales like Celsius or Fahrenheit, so it would be nice to have a component which internally works with Kelvin degrees and automatically applies conversion between Kelvin temperature scale and the one adopted by the user. + +In order to implement such a component, we can make a subclass of FormComponentPanel and leverage the convertInput and onBeforeRender methods: in the implementation of the convertInput method we will convert input value to Kelvin degrees while in the implementation of onBeforeRender method we will take care of converting the Kelvin value to the temperature scale adopted by the user. + +Our custom component will contain two children components: a text field to let user insert and edit a temperature value and a label to display the letter corresponding to user's temperature scale (F for Fahrenheit and C for Celsius). The resulting markup file is the following: + +[source,html] +---- +<html> +<head> +</head> +<body> + <wicket:panel> + Registered temperature: <input size="3" maxlength="3" + wicket:id="registeredTemperature"/> + <label wicket:id="mesuramentUnit"></label> + </wicket:panel> +</body> +</html> +---- + +As shown in the markup above FormComponentPanel uses the same <wicket:panel> tag used by Panel to define its markup. Now let's see the Java code of the new form component starting with the onInitialize() method: + +[source,java] +---- +public class TemperatureDegreeField extends FormComponentPanel<Double> { + + private TextField<Double> userDegree; + + public TemperatureDegreeField(String id) { + super(id); + } + + public TemperatureDegreeField(String id, IModel<Double> model) { + super(id, model); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + AbstractReadOnlyModel<String> labelModel=new AbstractReadOnlyModel<String>(){ + @Override + public String getObject() { + if(getLocale().equals(Locale.US)) + return "°F"; + return "°C"; + } + }; + + add(new Label("mesuramentUnit", labelModel)); + add(userDegree=new TextField<Double>("registeredTemperature", new + Model<Double>())); + userDegree.setType(Double.class); + } +---- + +Inside the onInitialize method we have created a read-only model for the label that displays the letter corresponding to the user's temperature scale. To determinate which temperature scale is in use, we retrieve the Locale from the session by calling Component's getLocale() method (we will talk more about this method in +<<_internationalization_with_wicket,paragraph 15>>). Then, if locale is the one corresponding to the United States, the chosen scale will be Fahrenheit, otherwise it will be considered as Celsius. + +In the final part of onInitialize() we add the two components to our custom form component. You may have noticed that we have explicitly set the type of model object for the text field to double. This is necessary as the starting model object is a null reference and this prevents the component from automatically determining the type of its model object. + +Now we can look at the rest of the code containing the convertInput and onBeforeRender methods: + +[source,java] +---- +// continued example + @Override + protected void convertInput() { + Double userDegreeVal = userDegree.getConvertedInput(); + Double kelvinDegree; + + if(getLocale().equals(Locale.US)){ + kelvinDegree = userDegreeVal + 459.67; + BigDecimal bdKelvin = new BigDecimal(kelvinDegree); + BigDecimal fraction = new BigDecimal(5).divide(new BigDecimal(9)); + + kelvinDegree = bdKelvin.multiply(fraction).doubleValue(); + }else{ + kelvinDegree = userDegreeVal + 273.15; + } + + setConvertedInput(kelvinDegree); + } + + @Override + protected void onBeforeRender() { + super.onBeforeRender(); + + Double kelvinDegree = (Double) getDefaultModelObject(); + Double userDegreeVal = null; + + if(kelvinDegree == null) return; + + if(getLocale().equals(Locale.US)){ + BigDecimal bdKelvin = new BigDecimal(kelvinDegree); + BigDecimal fraction = new BigDecimal(9).divide(new BigDecimal(5)); + + kelvinDegree = bdKelvin.multiply(fraction).doubleValue(); + userDegreeVal = kelvinDegree - 459.67; + }else{ + userDegreeVal = kelvinDegree - 273.15; + } + + userDegree.setModelObject(userDegreeVal); + } +} +---- + +Since our component does not directly receive the user input, convertInput() must read this value from the inner text field using FormComponent's getConvertedInput() method which returns the input value already converted to the type specified for the component (Double in our case). Once we have the user input we convert it to kelvin degrees and we use the resulting value to set the converted input for our custom component (using method setConvertedInput(T convertedInput)). + +Method onBeforeRender() is responsible for synchronizing the model of the inner textfield with the model of our custom component. To do this we retrieve the model object of the custom component with the getDefaultModelObject() method, then we convert it to the temperature scale adopted by the user and finally we use this value to set the model object of the text field. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/helloWorld.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/helloWorld.adoc b/wicket-user-guide/src/main/asciidoc/helloWorld.adoc new file mode 100644 index 0000000..b50e96c --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/helloWorld.adoc @@ -0,0 +1,27 @@ + +Wicket allows us to design our web pages in terms of components and containers, just like AWT does with desktop windows. +Both frameworks share the same component-based architecture: in AWT we have a _Windows_ instance which represents the physical windows containing GUI components (like text fields, radio buttons, drawing areas, etc...), in Wicket we have a _WebPage_ instance which represents the physical web page containing HTML components (pictures, buttons, forms, etc... ) . + +image::../img/uml-component.png[] + +["plantuml", "uml-component", "svg"] +.... +@startuml +package java.awt { + class Component + class Window extends Component + + Window "*" *-- "1" Component +} + +package org.apache.wicket { + class org.apache.wicket.Component + class WebPage extends org.apache.wicket.Component + + WebPage "*" *-- "1" org.apache.wicket.Component +} +@enduml +.... + +In both frameworks we find a base class for GUI components called _Component_. Wicket pages can be composed (and usually are) by many components, just like AWT windows are composed by Swing/AWT components. Both frameworks promote the reuse of presentation code and GUI elements building custom components. Even if Wicket already comes with a rich set of ready-to-use components, building custom components is a common practice when working with this framework. We'll learn more about custom components in the next chapters. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc new file mode 100644 index 0000000..c24e4dd --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc @@ -0,0 +1,23 @@ + +Wicket is available as a binary package on the main site http://wicket.apache.org[http://wicket.apache.org] . Inside this archive we can find the distribution jars of the framework. Each jar corresponds to a sub-module of the framework. The following table reports these modules along with a short description of their purpose and with the related dependencies: + +|=== +| *Module'sname* | *Description* | *Dependencies* +| wicket-core | Contains the main classes of the framework, like class _Component_ and _Application_. | wicket-request, wicket-util +| wicket-request | This module contains the classes involved into web request processing. | wicket-util +| wicket-util | Contains general-purpose utility classes for functional areas such as I/O, lang, string manipulation, security, etc... | None +| wicket-datetime | Contains special purpose components designed to work with date and time. | wicket-core +| wicket-bean-validation | Provides support for JSR 303 standard validation. | wicket-core +| wicket-devutils | Contains utility classes and components to help developers with tasks such as debugging, class inspection and so on. | wicket-core, wicket-extensions +|wicket-extensions | Contains a vast set of built-in components to build a rich UI for our web application (Ajax support is part of this module). | wicket-core +|wicket-auth-roles | Provides support for role-based authorization. | wicket-core +|wicket-ioc | This module provides common classes to support Inversion Of Control. It's used by both Spring and Guice integration module. | wicket-core +|wicket-guice | This module provides integration with the dependency injection framework developed by Google. | wicket-core, wicket-ioc +|wicket-spring | This module provides integration with Spring framework. | wicket-core, wicket-ioc +|wicket-velocity | This module provides panels and utility class to integrate Wicket with Velocity template engine. | wicket-core +|wicket-jmx| This module provides panels and utility class to integrate Wicket with Java Management Extensions. | wicket-core +|wicket-objectsizeof-agent | Provides integration with Java agent libraries and instrumentation tools. | wicket-core +|=== + +Please note that the core module depends on the utility and request modules, hence it cannot be used without them. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_2.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_2.adoc b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_2.adoc new file mode 100644 index 0000000..45e5226 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_2.adoc @@ -0,0 +1,98 @@ + +In this chapter we will see a classic Hello World! example implemented using a Wicket page with a built-in component called _Label_ (the code is from project the HelloWorldExample). Since this is the first example of the guide, before looking at Java code we will go through the common artifacts needed to build a Wicket application from scratch. + +NOTE: All the example projects presented in this document have been generated using Maven and the utility page at http://wicket.apache.org/start/quickstart.html[http://wicket.apache.org/start/quickstart.html] . *Appendix A* contains the instructions needed to use these projects and build a quickstart application using Apache Maven. All the artifacts used in the next example (files web.xml, HomePage.class and HomePage.html) are automatically generated by Maven. + +=== Wicket application structure + +A Wicket application is a standard Java EE web application, hence it is deployed through a web.xml file placed inside folder WEB-INF: + +image::../img/webinf.png[] + +_Illustration : The standard directory structure of a Wicket application_ + +The content of web.xml declares a servlet filter (class _org.apache.wicket.Protocol.http.WicketFilter_) which dispatches web requests to our Wicket application: + +[source,xml] +---- +<?xml version="1.0" encoding="UTF-8"?> +<web-app> + <display-name>Wicket Test</display-name> + <filter> + <filter-name>TestApplication</filter-name> + <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> + <init-param> + <param-name>applicationClassName</param-name> + <param-value>org.wicketTutorial.WicketApplication</param-value> + </init-param> + </filter> + <filter-mapping> + <filter-name>TestApplication</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> +</web-app> +---- + +Since this is a standard servlet filter we must map it to a specific set of URLs through the _<filter-mapping>_ tag). In the xml above we have mapped every URL to our Wicket filter. + +If we are using Servlet 3 or a later version, we can of course use a class in place of web.xml to configure our application. The following example uses annotation _WebFilter. + +[source,java] +---- +@WebFilter(value = "/*", initParams = { @WebInitParam(name = "applicationClassName", value = "com.mycompany.WicketApplication"), + @WebInitParam(name="filterMappingUrlPattern", value="/*") }) +public class ProjectFilter extends WicketFilter { + +} +---- + + + +NOTE: Wicket can be started in two modes named respectively DEVELOPMENT and DEPLOYMENT. The first mode activates some extra features which help application development, like resources monitoring and reloading, full stack trace rendering of exceptions, an AJAX debugger window, etc... The DEPLOYMENT mode turns off all these features optimizing performances and resource consumption. In our example projects we will use the default mode which is DEVELOPMENT. <<maven.adoc#_switching_wicket_to_deployment_mode,Chapter 24.1>> contains the chapter âSwitching Wicket to DEPLOYMENT modeâ where we can find further details about these two modes as well as the possible ways we have to set the desired one. In any case, DO NOT deploy your applications in a production environment without switching to DEPLOYMENT mode! + +=== The application class + +If we look back at web.xml we can see that we have provided the Wicket filter with a parameter called _applicationClassName_. This value must be the fully qualified class name of a subclass of _org.apache.wicket.Application_. This subclass represents our web application built upon Wicket and it's responsible for configuring it when the server is starting up. Most of the times our custom application class won't inherit directly from class _Application_, but rather from class _org.apache.wicket.protocol.http.WebApplication_ which provides a closer integration with servlet infrastructure. +Class _Application_ comes with a set of configuration methods that we can override to customize our application's settings. One of these methods is _getHomePage()_ that must be overridden as it is declared abstract: + +[source,java] +---- +public abstract Class<? extends Page> getHomePage() +---- + +As you may guess from its name, this method specifies which page to use as homepage for our application. +Another important method is _init()_: + +[source,java] +---- +protected void init() +---- + +This method is called when our application is loaded by the web server (Tomcat, Jetty, etc...) and is the ideal place to put our configuration code. The _Application_ class exposes its settings grouping them into interfaces (you can find them in package _org.apache.wicket.settings_). We can access these interfaces through getter methods that will be gradually introduced in the next chapters when we will cover the related settings. + +The current application's instance can be retrieved at any time calling static method _Application.get()_ in our code. We will give more details about this method in <<requestProcessing.adoc#_the_director_of_request_processing_requestcycle,chapter 9.3>>. The content of the application class from project HelloWorldExample is the following: + +[source,java] +---- +public class WicketApplication extends WebApplication +{ + @Override + public Class<? extends WebPage> getHomePage() + { + return HomePage.class; + } + + @Override + public void init() + { + super.init(); + // add your configuration here + } +} +---- + +Since this is a very basic example of a Wicket application, we don't need to specify anything inside the _init_ method. The home page of the application is the _HomePage_ class. In the next paragraph we will see how this page is implemented and which conventions we have to follow to create a page in Wicket. + +NOTE: Declaring a _WicketFilter_ inside web.xml descriptor is not the only way we have to kickstart our application. +If we prefer to use a servlet instead of a filter, we can use class _org.apache.wicket.protocol.http.WicketServlet_. See the JavaDoc for further details. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_3.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_3.adoc b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_3.adoc new file mode 100644 index 0000000..71374e9 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_3.adoc @@ -0,0 +1,62 @@ + + + +To complete our first Wicket application we must explore the home page class that is returned by the _Application_'s method _getHomePage()_ seen above. +In Wicket a web page is a subclass of _org.apache.wicket.WebPage_. This subclass must have a corresponding HTML file which will be used by the framework as template to generate its HTML markup. This file is a regular plain HTML file (its extension must be html). + +By default this HTML file must have the same name of the related page class and must be in the same package: + +image::../img/samepackage.png[] + +_Illustration :Page class and its related HTML file_ + +If you don't like to put class and html side by side (let's say you want all your HTML files in a separated folder) you can use Wicket settings to specify where HTML files can be found. We will cover this topic later in <<resources.adoc#_header_contributors_positioning,chapter 16.9>>. + +The Java code for the _HomePage_ class is the following: + +[source,java] +---- +package org.wicketTutorial; + +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.WebPage; + +public class HomePage extends WebPage { + public HomePage() { + add(new Label("helloMessage", "Hello WicketWorld!")); + } +} +---- + +Apart from subclassing _WebPage_, _HomePage_ defines a constructor that adds a _Label_ component to itself. +Method _add(Component component)_ is inherited from ancestor class _org.apache.wicket.MarkupContainer_ and is used to add children components to a web page. We'll see more about _MarkupContainer_ later in <<layout.adoc#_here_comes_the_inheritance,chapter 5.2>>. +Class _org.apache.wicket.markup.html.basic.Label_ is the simplest component shipped with Wicket. It just inserts a string (the second argument of its constructor) inside the corresponding HTML tag. +Just like any other Wicket component, _Label_ needs a textual id (_'helloMessage'_ in our example) to be instantiated. At runtime Wicket will use this value to find the HTML tag we want to bind to the component. This tag must have a special attribute called _wicket:id_ and its value must be identical to the component id (comparison is case-sensitive!). + +Here is the HTML markup for _HomePage_ (file HomePage.html): + +[source,html] +---- +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Apache Wicket HelloWorld</title> + </head> + <body> + + <div wicket:id="helloMessage"> + [Label's message goes here] + </div> + </body> +</html> +---- + +We can see that the _wicket:id_ attribute is set according to the value of the component id. If we run this example we will see the text _Hello WicketWorld!_ Inside a _<div>_ tag. + +NOTE: _Label_ replaces the original content of its tag (in our example _ <<_Label's message goes here>> +_) with the string passed as value (_Hello WicketWorld!_ in our example). + +WARNING: If we specify a _wicket:id_ attribute for a tag without adding the corresponding component in our Java code, Wicket will throw a _ComponentNotFound_ Exception. On the contrary if we add a component in our Java code without specifying a corresponding _wicket:id_ attribute in our markup, Wicket will throw a _WicketRuntimeException_. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_4.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_4.adoc b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_4.adoc new file mode 100644 index 0000000..40851cf --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_4.adoc @@ -0,0 +1,71 @@ + +The basic form of interaction offered by web applications is to navigate through pages using links. In HTML a link is basically a pointer to another resource that most of the time is another page. Wicket implements links with component _org.apache.wicket.markup.html.link.Link_, but due to the component-oriented nature of the framework, this component is quite different from classic HTML links. +Following the analogy with GUI frameworks, we can consider Wicket link as a âclickâ event handler: its purpose is to perform some actions (on server side!) when the user clicks on it. + +That said, you shouldn't be surprised to find an abstract method called _onClick()_ inside the _Link_ class. In the following example we have a page with a _Link_ containing an empty implementation of _onClick_: + +[source,java] +---- +public class HomePage extends WebPage { + public HomePage(){ + add(new Link("id"){ + @Override + public void onClick() { + //link code goes here + } + }); + } +} +---- + +By default after _onClick_ has been executed, Wicket will send back to the current page to the client web browser. If we want to navigate to another page we must use method _setResponsePage_ of class _Component_: + +[source,java] +---- +public class HomePage extends WebPage { + public HomePage(){ + add(new Link("id"){ + @Override + public void onClick() { + //we redirect browser to another page. + setResponsePage(AnotherPage.class); + } + }); + } +} +---- + +In the example above we used a version of _setResponsePage_ which takes as input the class of the target page. In this way a new instance of _AnotherPage_ will be created each time we click on the link. The other version of _setResponsePage_ takes in input a page instance instead of a page class: + +[source,java] +---- +@Override +public void onClick() { + //we redirect browser to another page. + AnotherPage anotherPage = new AnotherPage(); + setResponsePage(anotherPage); +} +---- + +The difference between using the first version of _setResponsePage_ rather than the second one will be illustrated in +<<_page_versioning_and_caching,chapter 8>>, when we will introduce the topic of stateful and stateless pages. For now, we can consider them as equivalent. + +Like many other Wicket components, _Link_ is lambda-friendly and comes with a factory method called _onClick_ which leverages lambda expressions to specify handler method: + +[source,java] +---- +public class HomePage extends WebPage { + public HomePage(){ + add(Link.onClick("id", () -> setResponsePage(AnotherPage.class)); + } +} +---- + +The lambda expression is converted into a _org.danekja.java.util.function.serializable.SerializableConsumer_, which is a serializable version of _java.util.function.Consumer<T>_ (we will see later why we need it to be serializable). + +Wicket comes with a rich set of link components suited for every need (links to static URL, Ajax-enhanced links, links to a file to download, links to external pages and so on). We will see them in +<<_wicket_links_and_url_generation,chapter 10>>. + +NOTE: We can specify the content of a link (i.e. the text of the picture inside it) with its method _setBody_. This method takes in input a generic Wicket model, which will be the topic of +<<_wicket_models_and_forms,chapter 11>>. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_5.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_5.adoc b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_5.adoc new file mode 100644 index 0000000..c27c264 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_5.adoc @@ -0,0 +1,4 @@ + +In this chapter we have seen the basic elements that compose a Wicket application. We have started preparing the configuration artifacts needed for our applications. As promised in <<helloWorld.adoc#_wicket_links,chapter 2.4>>, we needed to put in place just a minimal amount of XML with an application class and a home page. +Then we have continued our âfirst contactâ with Wicket learning how to build a simple page with a label component as child. This example page has shown us how Wicket maps components to HTML tags and how it uses both of them to generate the final HTML markup. +In the last paragraph we had a first taste of Wicket links and we have seen how they can be considered as a âclickâ event listener and how they can be used to navigate from a page to another. http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/howToSource.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/howToSource.adoc b/wicket-user-guide/src/main/asciidoc/howToSource.adoc new file mode 100644 index 0000000..c2d8faf --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/howToSource.adoc @@ -0,0 +1,17 @@ + +Most of the code you will find in this document is available as a https://github.com/bitstorm/Wicket-tutorial-examples[Git repository] and is licensed under the ASF 2.0. Examples are hosted live at {externalink:wicket.tutorial.examples.url}. To get a local copy of the repository you can run the clone command from shell: + +[source,java] +---- +git clone https://github.com/bitstorm/Wicket-tutorial-examples.git +---- + +If you aren't used to Git, you can simply download the whole source as a zip archive: + +image::../img/gitRepo.png[] + +The repository contains a multi-module Maven project. Every subproject is contained in the relative folder of the repository: + +image::../img/gitMavenPrj.png[] + +When the example code is used in the document, you will find the name of the subproject it belongs to. If you don't have any experience with Maven, you can read Appendix A where you can learn the basic commands needed to work with the example projects and to import them into your favourite IDE (NetBeans, IDEA or Eclipse). http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/http2push.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/http2push.adoc b/wicket-user-guide/src/main/asciidoc/http2push.adoc new file mode 100644 index 0000000..ce7006b --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/http2push.adoc @@ -0,0 +1,4 @@ + +With Wicket 8.0.0-M2 the new HTTP/2 push API is supported which uses the PushBuilder. + +The advantage of this is that you reduce the latency and thus save a lot of time in waiting for requests. http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/http2push/http2push_1.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/http2push/http2push_1.adoc b/wicket-user-guide/src/main/asciidoc/http2push/http2push_1.adoc new file mode 100644 index 0000000..f948203 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/http2push/http2push_1.adoc @@ -0,0 +1,75 @@ + +Currently there are different implementations for each server to be used until the Servlet 4.0 (JSR 369) specification reaches the final state. + +Current supported servers are: +* Eclipse Jetty 9.3+ +* Apache Tomcat 8.5+ +* RedHat Undertow 2+ + + +For the setup you need to follow those steps: + +1. Setup your server to use HTTP/2 and follow the instructions provided by the vendor specific documentation. (Because of HTTP/2 a HTTPS setup is also required) + +2. Add the respective dependency for your web server to provide the push functionality. +[source,java] +---- +<dependency> + <groupId>org.apache.wicket.experimental.wicket8</groupId> + <artifactId>wicket-http2-jetty</artifactId> + <!--<artifactId>wicket-http2-tomcat</artifactId>--> + <!--<artifactId>wicket-http2-undertow</artifactId>--> + <version>0.X-SNAPSHOT</version> +</dependency> +---- + +[arabic, start=3] +1. Use the PushHeader Item like in this example page: +Example: +[source,java] +---- +public class HTTP2Page extends WebPage +{ + private static final long serialVersionUID = 1L; + + private Response webPageResponse; + + private Request webPageRequest; + + public HTTP2Page() + { + webPageResponse = getRequestCycle().getResponse(); + webPageRequest = getRequestCycle().getRequest(); + add(new Label("label", "Label")); + } + + @Override + public void renderHead(IHeaderResponse response) + { + super.renderHead(response); + TestResourceReference instance = TestResourceReference.getInstance(); + response.render(CssHeaderItem.forReference(instance)); + response.render(new PushHeaderItem(this, webPageRequest, webPageResponse) + .push(Arrays.asList(new PushItem(instance)))); + } + + @Override + protected void setHeaders(WebResponse response) + { + // NOOP just disable caching + } +} +---- + +Basically the resource is pushed before the actual response of the component is send to the client (browser) and because of this the client does not need to send an additional request. + +The PushHeaderItem behaves like explained in the following steps: +* When a browser requests the page with an initial commit everything is going to be pushed with (200) +* When a browser requests the page a second time resources are not pushed (304) not modified, because of the actual ResourceReferences headers +* When a browser requests the page a second time and the markup of the page has changed everything is going to be pushed again (200) +* When a browser requests the page a second time and resource references has been changed but not the page markup, all changed resource references are shipped via separate requests + +Note: Chrome does not set cache headers if the https connection is not secure (self signed) / valid - so ensure that a valid https connection is available with your server. https://bugs.chromium.org/p/chromium/issues/detail?id=110649[Browser not caching files if HTTPS is used even if it's allowed by webserver via response headers] +If you want to change the cache behavior to not only look at the markup of the page and based on this proceed the push, override the method *protected Time getPageModificationTime()* of the PushHeaderItem (for more information have a look at the javadoc) + +To change the cache headers override the method *protected void applyPageCacheHeader()* of the PushHeaderItem http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/http2push/http2push_2.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/http2push/http2push_2.adoc b/wicket-user-guide/src/main/asciidoc/http2push/http2push_2.adoc new file mode 100644 index 0000000..5600f8b --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/http2push/http2push_2.adoc @@ -0,0 +1,61 @@ + +To create a server specific http/2 push support of the Wicket PushBuilder API just follow these steps: + +1. Add the following dependency to your projects pom.xml (and of course adjust the version) +[source,java] +---- +<dependency> + <groupId>org.apache.wicket.experimental.wicket8</groupId> + <artifactId>wicket-http2-core</artifactId> + <version>0.X-SNAPSHOT</version> +</dependency> +---- + +[arabic, start=2] +1. Add a text file called [org.apache.wicket.IInitializer] into the folder src/main/resources/META-INF/services/ + +2. Add a single line with the name of the IInitializer class example: [org.apache.wicket.http2.Initializer] to the created file + +3. Implement your own server specific PushBuilder class which implements the interface [org.apache.wicket.http2.markup.head.PushBuilder] This is an example how it was done for jetty: +[source,java] +---- +public class Jetty9PushBuilder implements PushBuilder +{ + @Override + public void push(HttpServletRequest httpServletRequest, String... paths) + { + Request request = RequestCycle.get().getRequest(); + HttpServletRequest httpRequest = (HttpServletRequest) request.getContainerRequest(); + org.eclipse.jetty.server.PushBuilder pushBuilder = + org.eclipse.jetty.server.Request.getBaseRequest(httpRequest).getPushBuilder(); + for (String path : paths) + { + pushBuilder.path(path); + } + pushBuilder.push(); + } +} +---- +[arabic, start=5] +1. Implement the class within the package [org.apache.wicket.http2.Initializer] and add your own server specific PushBuilder class to the Http2Settings. This is an example how it was done for jetty: +[source,java] +---- +public class Initializer implements IInitializer +{ + /** + * Initializes the push builder API of Jetty 9.3+ + */ + @Override + public void init(Application application) + { + Http2Settings http2Settings = Http2Settings.Holder.get(application); + http2Settings.setPushBuilder(new Jetty9PushBuilder()); + } + + @Override + public void destroy(Application application) + { + // NOOP + } +} +---- http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/i18n.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/i18n.adoc b/wicket-user-guide/src/main/asciidoc/i18n.adoc new file mode 100644 index 0000000..1140a6c --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/i18n.adoc @@ -0,0 +1,3 @@ + +In <<forms2.adoc#_form_validation_and_feedback_messages,chapter 12.2>> we have seen how the topic of localization is involved in the generation of feedback messages and we had a first contact with resource bundles. In this chapter we will continue to explore the localization support provided by Wicket and we will learn how to build pages and components ready to be localized in different languages. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/i18n/i18n_1.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/i18n/i18n_1.adoc b/wicket-user-guide/src/main/asciidoc/i18n/i18n_1.adoc new file mode 100644 index 0000000..413b047 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/i18n/i18n_1.adoc @@ -0,0 +1,28 @@ + + + +As we have seen in <<forms2.adoc#_form_validation_and_feedback_messages,paragraph 12.2>>, the infrastructure of feedback messages is built on top of Java internationalization (i18n) support, so it should not be surprising that the same infrastructure is used also for localization purpose. However, while so far we have used only the <ApplicationClassName>.properties file to store our custom messages, in this chapter we will see that also pages, components, validators and even Java packages can have their own resource bundles. This allows us to split bundles into multiple files keeping them close to where they are used. But before diving into the details of internationalization with Wicket, it's worthwhile to quickly review how i18n works under Java, see what classes are involved and how they are integrated into Wicket. + +NOTE: Providing a full description of Java support for i18n is clearly out of the scope of this document. If you need more informations about this topic you can find them in the JavaDocs and in the official http://docs.oracle.com/javase/tutorial/i18n/index.html[i18n tutorial] . + +=== Class Locale and ResourceBundle + +Class java.util.Locale represents a specific country or language of the world and is used in Java to retrieve other locale-dependent informations like numeric and date formats, the currency in use in a country and so on. Such kind of informations are accessed through special entities called resource bundles which are implemented by class _java.util.ResourceBundle_. Every resource bundle is identified by a full name which is built using four parameters: a base name (which is required), a language code, a country code and a variant (which are all optional). These three optional parameters are provided by an instance of Locale with its three corresponding getter methods: getLanguage(), getCountry() and getVariant(). Parameter language code is a lowercase ISO 639 2-letter code (like zh for Chinese, de for German and so on) while country code is an uppercase ISO 3166 2-letter code (like CN for China, DE for Germany and so on). The final full name will have the following structure (NOTE: tokens inside squared brackets are optional): + +[source,java] +---- +<base name>[_<language code>[_<COUNTRY_CODE>[_<variant code>]]] +---- + +For example a bundle with MyBundle as base name and localized for Mandarin Chinese (language code zh, country code CH, variant cmn) will have MyBundle_zh_CH_cmn as full name. A base name can be a fully qualified class name, meaning that it can include a package name before the actual base name. The specified package will be the container of the given bundle. For example if we use org.foo.MyBundle as base name, the bundle named MyBundle will be searched inside package org.foo. The actual base name (MyBundle in our example) will be used to build the full name of the bundle following the same rules seen above. +_ResourceBundle_ is an abstract factory class, hence it exposes a number of factory methods named getBundle to load a concrete bundle. Without going into too much details we can say that a bundle corresponds to a file in the classpath. To find a file for a given bundle, getBundle needs first to generate an ordered list of candidate bundle names. These names are the set of all possible full names for a given bundle. For example if we have org.foo.MyBundle as base name and the current locale is the one seen before for Mandarin Chinese, the candidate names will be: + +1. org.foo.MyBundle_zh_CH_cmn +2. org.foo.MyBundle_zh_CH +3. org.foo.MyBundle_zh +4. org.foo.MyBundle + +The list of these candidate names is generated starting from the most specific one and subtracting an optional parameter at each step. The last name of the list corresponds to the default resource bundle which is the most general name and is equal to the base name. Once that getBundle has generated the list of candidate names, it will iterate over them to find the first one for which is possible to load a class or a properties file. The class must be a subclass of _ResourceBundle_ having as class name the full name used in the current iteration. If such a class is not found, getBundle will try to locate a properties file having a file name equals to the current full name (Java will automatically append extension .properties to the full name). For example given the resource bundle of the previous example, Java will search first for class org.foo.MyBundle_zh_CH_cmn and then for file MyBundle_zh_CH_cmn.properties inside package org.foo. If no file is found for any of the candidate name s, a MissingResourceException will be thrown. Bundles contains local-dependent string resources identified by a key that is unique in the given bundle. So once we have obtained a valid bundle we can access these objects with method getString (String key). + +As we have seen before working with feedback messages, in Wicket most of the times we will work with properties files rather than with bundle classes. In <<forms2.adoc#_form_validation_and_feedback_messages,paragraph 12.2>> we used a properties file having as base name the class name of the application class and without any information about the locale. This file is the default resource bundle for a Wicket application. In <<i18n.adoc#_bundles_lookup_algorithm,paragraph 15.3>> we will explore the algorithm used in Wicket to locate the available bundles for a given component. Once we have learnt how to leverage this algorithm, we will be able to split our bundles into more files organized in a logical hierarchy. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/i18n/i18n_2.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/i18n/i18n_2.adoc b/wicket-user-guide/src/main/asciidoc/i18n/i18n_2.adoc new file mode 100644 index 0000000..4d2af29 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/i18n/i18n_2.adoc @@ -0,0 +1,161 @@ + + + +A component can get the current locale in use calling its method getLocale(). By default this method will be recursively called on component's parent containers until one of them returns a valid locale. If no one of them returns a locale, this method will get the one associated with the current user session. This locale is automatically generated by Wicket in accordance with the language settings of the browser. + +Developers can change the locale of the current session with Session's method setLocale (Locale locale): + +[source,java] +---- +Session.get().setLocale(locale) +---- + +=== Style and variation parameters for bundles + +In addition to locale's informations, Wicket supports two further parameters to identify a resource bundle: style and variation. Parameter style is a string value and is defined at session-level. To set/get the style for the current session we can use the corresponding setter and getter of class Session: + +[source,java] +---- +Session.get().setStyle("myStyle"); +Session.get().getStyle(); +---- + +If set, style's value contributes to the final full name of the bundle and it is placed between the base name and the locale's informations: + +[source,java] +---- +<base name>[_style][_<language code>[_<COUNTRY_CODE>[_<variant code>]]] +---- + +Wicket gives the priority to candidate names containing the style information (if available). The other parameter we can use for localization is variation. Just like style also variation is a string value, but it is defined at component-level. The value of variation is returned by Component's method getVariation(). By default this method returns the variation of the parent component or a null value if a component hasn't a parent (i.e. it's a page). If we want to customize this parameter we must overwrite method getVariation and make it return the desired value. + +Variation's value contributes to the final full name of the bundle and is placed before style parameter: + +[source,java] +---- +<base name>[_variation][_style][_<language code>[_<COUNTRY_CODE>[_<variant code>]]] +---- + + +=== Using UTF-8 for resource bundles + +Java uses the standard character set http://en.wikipedia.org/wiki/ISO/IEC_8859-1[ISO 8859-11] to encode text files like properties files. Unfortunately ISO 8859-1 does not support most of the extra-European languages like Chinese or Japanese. The only way to use properties files with such languages is to use escaped http://en.wikipedia.org/wiki/List_of_Unicode_characters[Unicode] characters, but this leads to not human-readable files. For example if we wanted to write the word 'website' in simplified Chinese (the ideograms are ç½ç«) we should write the Unicode characters _\u7F51\u7AD9_. +For this reason ISO 8859-11 is being replaced with another Unicode-compliant character encoding called UTF-8. Text files created with this encoding can contain Unicode symbols in plain format. +Wicket provides a useful convention to use properties file encoded with UTF-8. We just have to add prefix _.utf8._ to file extension (i.e. _.utf8.properties_). + +NOTE: If you want to use UTF-8 with your text files, make sure that your editor/IDE is actually using this character encoding. Some OS like Windows use a different encoding by default. + +=== Using XML files as resource bundles + +Starting from version 1.5, Java introduced the support for XML files as resource bundles. XML files are generally encoded with character sets UTF-8 or UTF-16 which support every symbol of the Unicode standard. In order to be a valid resource bundle the XML file must conform to the DTD available at http://java.sun.com/dtd/properties.dtd[http://java.sun.com/dtd/properties.dtd] . + +Here is an example of XML resource bundle taken from project LocalizedGreetings (file WicketApplication_zh.properties.xml) containing the translation in simplified Chinese of the greeting message âWelcome to the website!â: + +[source,xml] +---- +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> + <entry key="greetingMessage">欢è¿å 临æ¬ç½ç«ï¼</entry> +</properties> +---- + +To use XML bundles in Wicket we don't need to put in place any additional configuration. The only rule we have to respect with these files is to use properties.xml as extension while their base name follows the same rules seen so far for bundle names. + +=== Reading bundles from code + +Class Component makes reading bundles very easy with method getString(String key). This method searches for a resource with the given key looking into the resource bundles visited by the lookup algorithm illustrated in <<i18n.adoc#_bundles_lookup_algorithm,paragraph 15.3>>. For example if we have a greeting message with key greetingMessage in our application's resource bundle, we can read it from our component code with this instruction: + +[source,java] +---- +getString("greetingMessage"); +---- + +=== Localization of bundles in Wicket + +In <<forms2.adoc#_form_validation_and_feedback_messages,paragraph 12.2>> we have used as resource bundle the properties file placed next to our application class. This file is the default resource bundle for the entire application and it is used by the lookup algorithm if it doesn't find any better match for a given component and locale. If we want to provide localized versions of this file we must simply follow the rules of Java i18n and put our translated resources into another properties file with a name corresponding to the desired locale. For example project LocalizedGreetings comes with the default application's properties file ( WicketApplication.properties) containing a greeting message: + +[source,java] +---- +greetingMessage=Welcome to the site! +---- + +Along with this file we can also find a bundle for German (WicketApplication_de.properties) and another one in XML format for simplified Chinese (WicketApplication_zh.properties.xml). The example project consists of a single page (HomePage.java) displaying the greeting message. The current locale can be changed with a drop-down list and the possible options are English (the default one), German and simplified Chinese: + +image::../img/locale-german.png[] + +The label displaying the greeting message has a custom read-only model which returns the message with method getString. The initialization code for this label is this: + +[source,java] +---- +IModel<String> model = new AbstractReadOnlyModel<String>() { + @Override + public String getObject() { + return getString("greetingMessage"); + } +}; + +add(new Label("greetingMessage", model)); +---- + +Class _org.apache.wicket.model.AbstractReadOnlyModel_ is a convenience class for implementing read-only models. In this project we have implemented a custom read-only model for illustrative purposes only because Wicket already provides built-in models for the same task. We will see them in paragraph <<i18n.adoc#_internationalization_and_models,paragraph 15.5>>. + +The rest of the code of the home page builds the stateless form and the drop-down menu used to change the locale. + +[source,java] +---- +List<Locale> locales = Arrays.asList(Locale.ENGLISH, Locale.CHINESE, Locale.GERMAN); +final DropDownChoice<Locale> changeLocale = + new DropDownChoice<Locale>("changeLocale", new Model<Locale>(), locales); + +StatelessForm form = new StatelessForm("form"){ + @Override + protected void onSubmit() { + Session.get().setLocale(changeLocale.getModelObject()); + } +}; + +setStatelessHint(true); +add(form.add(changeLocale)) +---- + + +=== Localization of markup files + +Although resource bundles exist to extract local-dependent elements from our code and from UI components, in Wicket we can decide to provide different markup files for different locale settings. Just like standard markup files, by default localized markup files must be placed next to component's class and their file name must contain the locale's informations. In the following picture, CustomPanel comes with a standard (or default) markup file and with another one localized for German: + +image::../img/comp-with-markup-german.png[] + +When the current locale corresponds to German country (language code de), markup file CustomPanel_de.html will be used in place of the default one. + +=== Reading bundles with tag <wicket:message> + +String resources can be also retrieved directly from markup code using tag <wicket:message>. The key of the desired resource is specified with attribute key: + +[source,xml] +---- +<wicket:message key="greetingMessage">message goes here</wicket:message> +---- + +By default the resource value is not escaped for HTML entities. To do that use the _escape_ attribute: + +[source,xml] +---- +<wicket:message key="greetingMessage" escape="true">message goes here</wicket:message> +---- + + +_wicket:message_ can be adopted also to localize the attributes of a tag. The name of the attribute and the resource key are expressed as a colon-separated value. In the following markup the content of attribute _value_ will be replaced with the localized resource having 'key4value' as key: + +[source,html] +---- +<input type="submit" value="Preview value" wicket:message="value:key4value"/> +---- + +If we want to specify multiple attributes at once, we can separate them with a comma: + +[source,html] +---- +<input type="submit" value="Preview value" wicket:message="value:key4value, title:key4title"/> +---- + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/i18n/i18n_3.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/i18n/i18n_3.adoc b/wicket-user-guide/src/main/asciidoc/i18n/i18n_3.adoc new file mode 100644 index 0000000..6fc8570 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/i18n/i18n_3.adoc @@ -0,0 +1,108 @@ + + + +As we hinted at the beginning of this chapter, by default Wicket provides a very flexible algorithm to locate the resource bundles available for a given component. In this paragraph we will learn how this default lookup algorithm works and which options it offers to manage our bundle files. + +=== Localizing pages and panels + +Similarly to application class, also component classes can have their own bundle files having as base name the class name of the related component and placed in the same package. So for example if class CustomPanel is a custom panel we created, we can provide it with a default bundle file called CustomPanel.properties containing the textual resources used by this panel. This rule applies to page classes as well: + +image::../img/page-and-panel-bundle.png[] + +One fundamental thing to keep in mind when we work with these kinds of bundles is that the lookup algorithm gives priority to the bundles of the containers of the component that is requesting a localized resource. The more a container is higher in the hierarchy, the bigger is its priority over the other components. This mechanism was made to allow containers to overwrite resources used by children components. As a consequence the values inside the resource bundle of a page will have the priority over the other values with the same key defined in the bundles of children components. + +To better grasp this concept let's consider the component hierarchy depicted in the following picture: + +image::../img/custom-panel-bundle.png[] + +If CustomPanel tries to retrieve the string resource having 'message' as key, it will get the value 'Wellcome!' and not the one defined inside its own bundle file. + +The default message-lookup algorithm is not limited to component hierarchy but it also includes the class hierarchy of every component visited in the search strategy described so far. This makes bundle files inheritable, just like markup files. When the hierarchy of a container component is explored, any ancestor has the priority over children components. Consider for example the hierarchy in the following picture: + +image::../img/custom-panel-bundle2.png[] + +Similarly to the previous example, the bundle owned by CustomPanel is overwritten by the bundle of page class BasePage (which has been inherited by CustomPage). + +=== Component-specific resources + +In order to make a resource specific for a given child component, we can prefix the message key with the id of the desired component. Consider for example the following code and bundle of a generic page: + +Page code: + +[source,java] +---- +add(new Label("label",new ResourceModel("labelValue"))); +add(new Label("anotherLabel",new ResourceModel("labelValue"))); +---- + +Page bundle: + +[source,java] +---- +labelValue=Default value +anotherLabel.labelValue=Value for anotherLabel +---- + +Label with id anotherLabel will display the value 'Value for anotherLabel' while label label will display 'Default value'. In a similar fashion, parent containers can specify a resource for a nested child component prepending also its relative path (the path is dot-separated): + +Page code: + +[source,java] +---- +Form form = new Form("form"); +form.add(new Label("anotherLabel",new ResourceModel("labelValue"))); +add(form); +---- + +Page bundle: + +[source,java] +---- +labelValue=Default value +anotherLabel.labelValue=Value for anotherLabel +form.anotherLabel.labelValue=Value for anotherLabel inside form +---- + +With the code and the bundle above, the label inside the form will display the value 'Value for anotherLabel inside form'. + +=== Package bundles + +If no one of the previous steps can find a resource for the given key, the algorithm will look for package bundles. These bundles have _wicket-package_ as base name and they can be placed in one of the package of our application: + +image::../img/package-bundles.png[] + +Packages are traversed starting from the one containing the component requesting for a resource and going up to the root package. + +=== Bundles for feedback messages + +The algorithm described so far applies to feedback messages as well. In case of validation errors, the component that has caused the error will be considered as the component which the string resource is relative to. Furthermore, just like application class and components, validators can have their own bundles placed next to their class and having as base name their class name. This allows us to distribute validators along with the messages they use to report errors: + +image::../img/validator-with-bundle.png[] + +Validator's resource bundles have the lowest priority in the lookup algorithm. They can be overwritten by resource bundles of components, packages and application class. + +=== Extending the default lookup algorithm + +Wicket implements the default lookup algorithm using the strategy pattern. The concrete strategies are abstracted with the interface _org.apache.wicket.resource.loader.IStringResourceLoader_. By default Wicket uses the following implementations of _IStringResourceLoader_ (sorted by execution order): + +1. *ComponentStringResourceLoader:* implements most of the default algorithm. It searches for a given resource across bundles from the container hierarchy, from class hierarchy and from the given component. +2. *PackageStringResourceLoader:* searches into package bundles. +3. *ClassStringResourceLoader:* searches into bundles of a given class. By default the target class is the application class. +4. *ValidatorStringResourceLoader:* searches for resources into validator's bundles. A list of validators is provided by the form component that failed validation. +5. *InitializerStringResourceLoader:* this resource allows internationalization to interact with the initialization mechanism of the framework that will be illustrated in <<advanced.adoc#_wicket_events_infrastructure,paragraph 18.3>>. +6. *NestedStringResourceLoader:* allows to replace nested Strings and can be chained up with other resource loader + +Developer can customize lookup algorithm removing default resource loaders or adding custom implementations to the list of the resource loaders in use. This task can be accomplished using method getStringResourceLoaders of setting class _org.apache.wicket.settings.ResourceSettings_: + +[source,java] +---- +@Override +public void init() +{ + super.init(); + //retrieve ResourceSettings and then the list of resource loaders + List<IStringResourceLoader> resourceLoaders = getResourceSettings(). + getStringResourceLoaders(); + //customize the list... +---- + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/i18n/i18n_4.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/i18n/i18n_4.adoc b/wicket-user-guide/src/main/asciidoc/i18n/i18n_4.adoc new file mode 100644 index 0000000..674bd67 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/i18n/i18n_4.adoc @@ -0,0 +1,73 @@ + + + +Components that inherit from _AbstractChoice_ (such as _DropDownChoice_, _CheckBoxMultipleChoice_ and _RadioChoice_) must override method _localizeDisplayValues_ and make it return true to localize the values displayed for their choices. By default this method return false so values are displayed as they are. Once localization is activated we can use display values as key for our localized string resources. In project LocalizedChoicesExample we have a drop-down list that displays four colors (green, red, blue, and yellow) which are localized in three languages (English, German and Italian). The current locale can be changed with another drop-down menu (in a similar fashion to project _LocalizedGreetings_). The code of the home page and the relative bundles are the following: + +Java code: + +[source,java] +---- +public HomePage(final PageParameters parameters) { + super(parameters); + + List<Locale> locales = Arrays.asList(Locale.ENGLISH, Locale.ITALIAN, Locale.GERMAN); + List<String> colors = Arrays.asList("green", "red", "blue", "yellow"); + + final DropDownChoice<Locale> changeLocale = new DropDownChoice<Locale>("changeLocale", + new Model<Locale>(), locales); + + StatelessForm form = new StatelessForm("form"){ + @Override + protected void onSubmit() { + Session.get().setLocale(changeLocale.getModelObject()); + } + }; + + DropDownChoice<String> selectColor = new DropDownChoice<String>("selectColor", new + Model<String>(), colors){ + @Override + protected boolean localizeDisplayValues() { + return true; + } + }; + + form.add(selectColor); + add(form.add(changeLocale)); + } +---- + +Default bundle (English): + +[source,java] +---- +selectColor.null=Select a color +green=Green +red=Red +blue=Blue +yellow=Yellow +---- + +German bundle: + +[source,java] +---- +selectColor.null=Wählen Sie eine Farbe +green=Grün +red=Rot +blue=Blau +yellow=Gelb +---- + +Italian bundle: + +[source,java] +---- +selectColor.null=Scegli un colore +green=Verde +red=Rosso +blue=Blu +yellow=Giallo +---- + +Along with the localized versions of colors names, in the bundles above we can also find a custom value for the placeholder text (âSelect a color â) used for null value. The resource key for this resource is 'null' or '<component id>.null' if we want to make it component-specific. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/i18n/i18n_5.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/i18n/i18n_5.adoc b/wicket-user-guide/src/main/asciidoc/i18n/i18n_5.adoc new file mode 100644 index 0000000..40c88dd --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/i18n/i18n_5.adoc @@ -0,0 +1,114 @@ + + + +Internationalization is another good chance to taste the power of models. Wicket provides two built-in models to better integrate our components with string resources: they are ResourceModel and StringResourceModel. + +=== ResourceModel + +Model _org.apache.wicket.model.ResourceModel_ acts just like the read-only model we have implemented in <<i18n.adoc#_bundles_lookup_algorithm,paragraph 15.3>>. It simply retrieves a string resource corresponding to a given key: + +[source,java] +---- +//build a ResourceModel for key 'greetingMessage' +new ResourceModel("greetingMessage"); +---- + +We can also specify a default value to use if the requested resource is not found: + +[source,java] +---- +//build a ResourceModel with a default value +new ResourceModel("notExistingResource", "Resource not found."); +---- + +=== StringResourceModel + +Model _org.apache.wicket.model.StringResourceModel_ allows to work with complex and dynamic string resources containing parameters and property expressions. The basic constructor of this model takes in input a resource key and another model. This further model can be used by both the key and the related resource to specify dynamic values with property expressions. For example let's say that we are working on an e-commerce site which has a page where users can see an overview of their orders. To handle the state of user's orders we will use the following bean and enum (the code is from project StringResourceModelExample): + +Bean: + +[source,java] +---- +public class Order implements Serializable { + + private Date orderDate; + private ORDER_STATUS status; + + public Order(Date orderDate, ORDER_STATUS status) { + super(); + this.orderDate = orderDate; + this.status = status; + } + //Getters and setters for private fields +} +---- + +Enum: + +[source,java] +---- +public enum ORDER_STATUS { + + PAYMENT_ACCEPTED(0), + IN_PROGRESS(1), + SHIPPING(2), + DELIVERED(3); + + private int code; + //Getters and setters for private fields +} +---- + +Now what we want to do in this page is to print a simple label which displays the status of an order and the date on which the order has been submitted. All the informations about the order will be passed to a StringResourceModel with a model containing the bean Order. The bundle in use contains the following key/value pairs: + +[source,java] +---- +orderStatus.0=Your payment submitted on ${orderDate} has been accepted. +orderStatus.1=Your order submitted on ${orderDate} is in progress. +orderStatus.2=Your order submitted on ${orderDate} has been shipped. +orderStatus.3=Your order submitted on ${orderDate} has been delivered. +---- + +The values above contain a property expression (${orderDate}) that will be evaluated on the data object of the model. The same technique can be applied to the resource key in order to load the right resource according to the state of the order: + +[source,java] +---- +Order order = new Order(new Date(), ORDER_STATUS.IN_PROGRESS); +add(new Label("orderStatus", new StringResourceModel("orderStatus.${status.code}", Model.of(order)))); +---- + +As we can see in the code above also the key contains a property expression (${status.code}) which makes its value dynamic. In this way the state of an object (an Order in our example) can determinate which resource will be loaded by StringResourceModel. If we don't use properties expressions we can provide a null value as model and in this case StringResourceModel will behave exactly as a ResourceModel. StringResourceModel supports also the same parameter substitution used by standard class _java.text.MessageFormat_. + +Parameters can be generic objects but if we use a model as parameter, StringResourceModel will use the data object inside it as actual value (it will call getObject on the model). Parameters are passed as a vararg argument with method _setParameters(Object... parameters)_. Here is an example of usage of parameter substitution: + +Java code: + +[source,java] +---- +PropertyModel propertyModel = new PropertyModel<Order>(order, "orderDate"); +//build a string model with two parameters: a property model and an integer value +StringResourceModel srm = new StringResourceModel("orderStatus.delay").setParameters(propertyModel, 3); +---- + +Bundle: + +[source,java] +---- +orderStatus.delay=Your order submitted on ${0} has been delayed by {1} days. +---- + +One further parameter we can specify when we build a StringResourceModel is the component that must be used by the lookup algorithm. Normally this parameter is not relevant, but if we need to use a particular bundle owned by a component not considered by the algorithm, we can specify this component as second parameter. If we pass all possible parameters to StringResourceModel's constructor we obtain something like this: + +[source,java] +---- +new StringResourceModel("myKey", myComponent, myModel); +---- + +Default value is supported as well, both as string model or as string value: + +[source,java] +---- +new StringResourceModel("myKey", myComponent, myModel).setDefaultValue("default"); +---- + + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/i18n/i18n_6.adoc ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/i18n/i18n_6.adoc b/wicket-user-guide/src/main/asciidoc/i18n/i18n_6.adoc new file mode 100644 index 0000000..64ce699 --- /dev/null +++ b/wicket-user-guide/src/main/asciidoc/i18n/i18n_6.adoc @@ -0,0 +1,5 @@ + + + +Internationalization is a mandatory step if we want to take our applications (and our business!) abroad. Choosing the right strategy to manage our localized resources is fundamental to avoid to make a mess of them. In this chapter we have explored the built-in support for localization provided by Wicket, and we have learnt which solutions it offers to manage resource bundles. In the final part of the chapter we have seen how to localize the options displayed by a component (such as DropDownChoice or RadioChoice) and we also introduced two new models specifically designed to localize our components without introducing in their code any detail about internationalization. + http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/AJAX-tree-repeater.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/AJAX-tree-repeater.png b/wicket-user-guide/src/main/asciidoc/img/AJAX-tree-repeater.png new file mode 100644 index 0000000..855b1b2 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/AJAX-tree-repeater.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/CallbackURLExample-screenshot.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/CallbackURLExample-screenshot.png b/wicket-user-guide/src/main/asciidoc/img/CallbackURLExample-screenshot.png new file mode 100644 index 0000000..ae56f03 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/CallbackURLExample-screenshot.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/EjbInjectionExample.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/EjbInjectionExample.png b/wicket-user-guide/src/main/asciidoc/img/EjbInjectionExample.png new file mode 100644 index 0000000..6a8908b Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/EjbInjectionExample.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/InterComponentsEventsExample-screenshot.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/InterComponentsEventsExample-screenshot.png b/wicket-user-guide/src/main/asciidoc/img/InterComponentsEventsExample-screenshot.png new file mode 100644 index 0000000..9c563e0 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/InterComponentsEventsExample-screenshot.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/JMX-console.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/JMX-console.png b/wicket-user-guide/src/main/asciidoc/img/JMX-console.png new file mode 100644 index 0000000..01fa521 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/JMX-console.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/JMX-console2.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/JMX-console2.png b/wicket-user-guide/src/main/asciidoc/img/JMX-console2.png new file mode 100644 index 0000000..94ef21b Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/JMX-console2.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/JMX-console3.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/JMX-console3.png b/wicket-user-guide/src/main/asciidoc/img/JMX-console3.png new file mode 100644 index 0000000..a035355 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/JMX-console3.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/JMX-console4.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/JMX-console4.png b/wicket-user-guide/src/main/asciidoc/img/JMX-console4.png new file mode 100644 index 0000000..6fce925 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/JMX-console4.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/JMX-new-connection.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/JMX-new-connection.png b/wicket-user-guide/src/main/asciidoc/img/JMX-new-connection.png new file mode 100644 index 0000000..a249000 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/JMX-new-connection.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/apache-wicket.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/apache-wicket.png b/wicket-user-guide/src/main/asciidoc/img/apache-wicket.png new file mode 100644 index 0000000..7d4d922 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/apache-wicket.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/asf_logo.gif ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/asf_logo.gif b/wicket-user-guide/src/main/asciidoc/img/asf_logo.gif new file mode 100644 index 0000000..c338757 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/asf_logo.gif differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/authorization-access-denied.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/authorization-access-denied.png b/wicket-user-guide/src/main/asciidoc/img/authorization-access-denied.png new file mode 100644 index 0000000..a997794 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/authorization-access-denied.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/autocomplete-example-screenshot.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/autocomplete-example-screenshot.png b/wicket-user-guide/src/main/asciidoc/img/autocomplete-example-screenshot.png new file mode 100644 index 0000000..ab3ccdb Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/autocomplete-example-screenshot.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/browser-back.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/browser-back.png b/wicket-user-guide/src/main/asciidoc/img/browser-back.png new file mode 100644 index 0000000..f869c59 Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/browser-back.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/choice-form-screenshot.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/choice-form-screenshot.png b/wicket-user-guide/src/main/asciidoc/img/choice-form-screenshot.png new file mode 100644 index 0000000..f270fdf Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/choice-form-screenshot.png differ http://git-wip-us.apache.org/repos/asf/wicket/blob/533c2d36/wicket-user-guide/src/main/asciidoc/img/class-diag-IFormSubmittingComponent.png ---------------------------------------------------------------------- diff --git a/wicket-user-guide/src/main/asciidoc/img/class-diag-IFormSubmittingComponent.png b/wicket-user-guide/src/main/asciidoc/img/class-diag-IFormSubmittingComponent.png new file mode 100644 index 0000000..68e8d6f Binary files /dev/null and b/wicket-user-guide/src/main/asciidoc/img/class-diag-IFormSubmittingComponent.png differ