Craig Tataryn started his career as a Visual Basic programmer, but don't hold that against him!  The system he helped create was a cutting edge, n-tiered revenue collection system whose transactions per second metric was off the charts!  Around the year 2000 he discovered Struts and never looked back.  A professional Java developer for close to a decade, Craig has worked on a wide variety of projects ranging from Recruiting, Purchase order, Revenue collection and Mortgage systems.  More recently Craig has written web services for children's educational toys and has honed his skills on Wicket, Facebook and iPhone application development.  "I love to learn and more importantly I love to teach.  Hoarding knowledge is one of the most petty and selfish things you can do, especially as a contractor.  This is why I always make it a point to document and share my knowledge with my client's employees" Craig has posted 2 posts at DZone. View Full User Profile

Wicket Tutorial Series: Setting Up the Project

03.10.2009
| 20127 views |
  • submit to reddit
Your IDE

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.

Spring

The 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>
  1. wicket-spring-annot: allows us to wire our Wicket application via handy dependency injection annotations (i.e. @SpringBean, see Wicket documentation for more detail)
  2. spring: is just the core spring libraries
  3. spring-test: is a set of Spring integration classes for Unit testing
  4. 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>
<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

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>
  1. hibernate-annotations: used so we can annotate our model classes with mapping information, instead of having to create a separate mysticpaste.hbm.xml file.
  2. c3p0: provides a connection pooling library Hibernate can use
  3. commons-dbcp: another connection pooling library, we’ll add it as well and decide whether to use it or c3p0 later
  4. 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.

Database

For 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 -->
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
Servlets

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.

Filters

Filters 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.

Profiles

To 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 

Published at DZone with permission of its author, Craig Tataryn.

(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

Removing the wicket-archetype-quickstart directory and rerunning the command made it work.  Thanks for the help.

Shane Hayes replied on Thu, 2009/09/03 - 3:16pm

The maven create project does not get the same defaults as creating a native wicket project (in netbeans), it is missing things like the header and navigation defaults.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.