Wicket Tutorial Series: Setting Up the Project
Sooner or later you’re going to want to crack open your IDE and start hacking away. Maven makes this extremely easy by allowing you to create IDE specific project files based off of the Maven pom.xml file.
Eclipse
mvn eclipse:eclipse
For eclipse you’ll also have to set the M2_REPO classpath variable for the workspace your project resides under. Do this by entering the following command:
mvn -Declipse.workspace=<your_workspace_location> eclipse:add-maven-repo
IntelliJ IDEA
mvn idea:idea -OR- in IDEA 7+ simply open the pom.xml file
Netbeans
Netbeans supports maven out of the box, just “Open Project” and choose the mysticpaste directory that contains the pom.xml file
When generating the project files through Maven, the project is setup such that classpath entries point to your local Maven repository (i.e. ~/.m2/repository, or C:Documents and Settingsyourusername.M2repository on Windows). It also sets up src/main/java, src/main/resources as “source folders”. You may add other folders to the source folder list as per your IDE if needed, the only thing you have to remember is if you ever use mvn eclipse:clean followed by mvn eclipse:eclipse again, those other source folders will have to be readded through your IDE. Instead, you should add the source/resource folders directly to your pom.xml, this way they will be maintained.
SpringThe Mystic Paste application will use Spring, and really you should too. Unless you have been hiding under a rock or work in a corporate environment so lame as to which technologies newer than 2002 are forbidden you should learn to accept Spring as a defacto standard. Dependency injection for the win!
We add the following to our pom.xml:
<!-- Note: versions have been left off intentionally to future proof this article -->
<dependency> <!-- 1 -->
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-spring-annot</artifactId>
</dependency>
<dependency> <!-- 2 -->
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</dependency>
<dependency> <!-- 3 -->
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency> <!-- 4 -->
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
- wicket-spring-annot: allows us to wire our Wicket application via handy dependency injection annotations (i.e. @SpringBean, see Wicket documentation for more detail)
- spring: is just the core spring libraries
- spring-test: is a set of Spring integration classes for Unit testing
- spring-tx: is the Spring Transaction Management api for declarative transactions
web.xml additions for Spring
In order for Spring to manage our Wicket application we need to setup the Wicket filter with a Spring-aware application factory. This allows us to wire our Wicket Application class in our applicationContext.xml file, which is really handy if you have a services and configuration settings you want to inject into the Wicket Application object so the rest of your application can access them. To do this, we change the original Wicket filter like so:
<filter>
<filter-name>wicket.mysticpaste</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<!--<param-name>applicationClassName</param-name>-->
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
</filter>
As well, we want our Spring context to be available to our webapp if ever there is a need for one of our pages to access the Spring managed beans directly:
<context-param>Hibernate
<param-name>contextConfigLocation</param-name>
<param-value>classpath:com/mysticcoders/mysticpaste/spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Hibernate is our ORM of choice, it will allow us to persist and retrieve our model objects to and from the underlying database, whatever that database may be.
We add the following to our pom.xml:
<!-- Note: versions have been left off intentionally to future proof this article -->
<dependency> <!-- 1 -->
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
</dependency>
<dependency> <!-- 2 -->
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</dependency>
<dependency> <!-- 3 -->
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
<dependency> <!-- 4 -->
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.0.1B</version>
</dependency>
- hibernate-annotations: used so we can annotate our model classes with mapping information, instead of having to create a separate mysticpaste.hbm.xml file.
- c3p0: provides a connection pooling library Hibernate can use
- commons-dbcp: another connection pooling library, we’ll add it as well and decide whether to use it or c3p0 later
- jta: this is the Java Transaction API which is needed by Hibernate (Hibernate provides an implementation of the API)
web.xml additions for Hibernate
To have a Hibernate Session open and ready for our webapplication during a Request Cycle we need to setup a Hibernate filter like so (otherwise, good luck getting lazy loading working!):
<filter>
<filter-name>open.hibernate.session.in.view</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<!-- Important! This filter mapping must come before Wicket's! -->
<filter-mapping>
<filter-name>open.hibernate.session.in.view</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
As the comment states above, make sure this filter-mapping exists *before* your wicket.mysticpaste filter or else it just plain won’t work.
DatabaseFor the Mystic Paste we decided to use the freely available PostgreSQL. Adding support for PostgreSQL is very easy, unlike with some of the commercial DBMSes where you have to download and install their JDBC driver into your repository. To add support for Postgres, we simply add the following to our pom.xml:
<!-- Note: versions have been left off intentionally to future proof this article -->Servlets
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
Regardless of which webapplication framework you choose there are just some times when a plain jane Servlet comes in really handy. If you have a need for Servlets and the Servlet must have access to the Wicket session add the following to your web.xml:
<filter>
<filter-name>wicket.session</filter-name>
<filter-class>org.apache.wicket.protocol.http.servlet.WicketSessionFilter</filter-class>
<init-param>
<param-name>filterName</param-name>
<param-value>wicket.mysticpaste</param-value>
</init-param>
</filter>
And then, after your other filter-mappings add the following (assuming you mount your servlet-mappings under /servlet/):
<filter-mapping>
<filter-name>wicket.session</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
Maven Filters and Profiles
In order to build our Mystic Paste project for various environments (DEV/QA/PROD) we need to implement both Maven profiles and filters.
FiltersFilters allow you to place variables inside your configuration files and have those variables filled in durring build time. This is very handy for setting environment specific things such as database connection information.
Enabling filters is quite easy, we open up the pom.xml file and find the section for <resources> and set the value for the <filtering> element to true as follows:
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
.
.
.
</resources>
But for filtering to work, we need to specify a filters file. It’s not enough to specify only one filter file because we need to specify different filters per environment and we’ll do that by using Maven Profiles.
ProfilesTo setup a profile, create a new set of elements following the <build> section in your pom.xml file. Like so:
<properties>
<!-- default env when no profile is specified -->
<env>DEV</env>
</properties>
<profiles>
<profile>
<id>DEV</id>
<properties>
<env>DEV</env>
</properties>
</profile>
<profile>
<id>QA</id>
<properties>
<env>QA</env>
</properties>
</profile>
<profile>
<id>PROD</id>
<properties>
<env>PROD</env>
</properties>
</profile>
</profiles>
and just above your <resources> tag underneith your <build> tag you would add the following elements:
<build>
<finalName>mysticpaste</finalName>
<filters>
<filter>src/main/filters/filters-${env}.properties</filter>
</filters>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
src/main/filters will contain the following files.
|-- pom.xml
|-- src
| `-- main
| |-- filters
| | `-- filters-DEV.properties
| | `-- filters-QA.properties
| | `-- filters-PROD.properties
filters-DEV.properties
jdbc.url=jdbc:postgresql://localhost:5432/mysticpaste
jdbc.user=mysticpaste
jdbc.password=password
image.upload.path=/tmp/pasetbin/userimages
image.upload.size.limit=4096K
filters-PROD.properties
jdbc.url=jdbc:postgresql://192.168.2.10:5432/mysticpaste
jdbc.user=mysticpaste
jdbc.password=CrYp71c
image.upload.path=/mysticpaste/userimages
image.upload.size.limit=4096K
Now within any file under src/main/resources that has variables of the form ${variable.name} will have those variables replaced with the values specified in the proper filters file located under src/main/filters. For instance here is an example of a Spring applicationContext.xml file which will be interpolated with proper variables values at build time:
applicationContext.xml
<bean id="photoServiceConfig" class="com.mysticcoders.mysticpaste.services.ImageServiceConfig">
<property name="absoluteFilePath" value="${image.upload.path}"/>
<property name="imageSizeLimit" value="${image.upload.size.limit}"/>
</bean>
<bean id="photoService" class="com.mysticcoders.mysticpaste.services.ImageManagementServiceImpl">
<constructor-arg ref="photoServiceConfig"/>
<property name="photoManagementDao" ref="photoDao"/>
</bean>
To determine which filters file will be used depends on the profile chosen when building. For example, to build to production using the filters-PROD.properties we would execute the following:
mvn clean deploy -P PROD
The profile you use with the -P switch must match one of the values of the <ID> element for a profile.
Conclusion
Although it’s quite easy to get started with the Maven QuickStart project it is sometimes a bit frustrating putting some of the additonal pieces together. Building to several environments, setting up depenencies not included in the QuickStart project and strucuturing your project in an effort to make life easy for yourself as a developer and for your designer.
I hope our Day 1 tutorial leaves you with a good sense of how a Wicket project is setup, now we can move onto coding the app!
In the next four days we will be covering:
- Writing the Tests
- Designing the backend
- Designing the Wicket components
- Putting it all together
Mystic Coders, LLC has been coding web magic since 2000. Mystic is a full-service Development Agency specializing in Enterprise development with Java. They are usually involved in developing enterprise-grade software for companies large and small, and have experience working in diverse industries, including b2b, b2c, and government-based projects. Mystic has done work with large companies such as LeapFrog, Nestlé, Harrah's Entertainment and the Los Angeles Conventions & Visitor's Bureau, among others. Andrew Lombardi, CTO of Mystic, is available for speaking engagements.
For more about Mystic, check us out at http://www.mysticcoders.com
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





Comments
Bjorn Vandenheede replied on Wed, 2009/03/11 - 9:54am
How come the quickstart command of Wicket just doesn't work for me? Trying the following:
mvn -e archetype:create -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.3.5 -DgroupId=com.mysticcoders -DartifactId=mysticpaste
Just gives me
...
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Error creating from archetype
Embedded error: The META-INF/maven/archetype.xml descriptor cannot be found.
[INFO] ------------------------------------------------------------------------
[INFO] Trace
org.apache.maven.lifecycle.LifecycleExecutionException: Error creating from archetype
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:583)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:512)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:482)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.jav
a:330)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:227)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:142)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:336)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:129)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:287)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: org.apache.maven.plugin.MojoExecutionException: Error creating from archetype
at org.apache.maven.plugin.archetype.MavenArchetypeMojo.execute(MavenArchetypeMojo.java:197)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:451)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:558)
... 16 more
Caused by: org.apache.maven.archetype.ArchetypeDescriptorException: The META-INF/maven/archetype.xml descriptor cannot b
e found.
at org.apache.maven.archetype.DefaultArchetype.createArchetype(DefaultArchetype.java:185)
at org.apache.maven.plugin.archetype.MavenArchetypeMojo.execute(MavenArchetypeMojo.java:188)
... 18 more
Is this a wicket archtype problem, or something wrong with my maven setup (2.0.9), ...?
Craig Tataryn replied on Wed, 2009/03/11 - 12:32pm
in response to:
Bjorn Vandenheede
It's quite possible your local maven repo is corrupted. Do this, navigate to your local repo (i.e. ~/.m2/repository) and delete the folder under org/apache/wicket that pertains to the quickstart archetype and try again. It should re-download the archetype from the maven repos.
Good luck!
Bjorn Vandenheede replied on Wed, 2009/03/11 - 5:08pm
Shane Hayes replied on Thu, 2009/09/03 - 3:16pm