Table of Contents
- Introduction
- Libraries and Roles
- Environment Configuration
- If you have to troubleshoot!
- Simple Application
- Application Architecture (MVC)
- Making “Magical Stuff”
- Mapping! POJO and DAO “Model”
- Creating Pivot WTKX “View”
- Linking with Magical Stuff “Controller”
- Summary
- History
0. Introduction
Before starting this article, I want to clarify that this is not “My RPG Game” but “Our RPG Game”, in reality this is “Our MVC Game”, by playing with a new Rich Internet Application (RIA) from Apache called Pivot.
Pivot! What's? “Apache Pivot is an open-source platform for building rich internet applications in Java. It combines the enhanced productivity and usability features of a modern RIA toolkit with the robustness of the Java platform. Pivot applications are written using a combination of Java and XML and can be run either as an applet or as a standalone, optionally offline, desktop application.”
Desktop application! Really? Yes it's our simple application for demonstration by using Model–View–Controller (MVC) Model–view–controller architecture without using any other MVC frameworks and/or libraries.
1. Libraries and Roles
Like classical RPG games (Ragnarok Game), we have three classical “Classes”, “Jobs” or “Races”. Swordsmen, Priests and Wizards, for each “Job” we have libraries (jars) or frameworks to reference it in this application.
Let's proceed to discuss about our heros:
- Pivot plays Swordsman's role, because he is at the front-end and defending the application from user attacks (mouse clicks, invalid data, etc.) by his shield “modal and pop-up messages” =), it's funny?
- Spring plays a Priest's role, oh no! Spring is a Wizard because he uses a magical configuration for linking between all application libraries and/or frameworks.
- Hibernate plays a Priest's role, because he heals and blesses Pivot with data retrieved from the database for not losing on the user front.
Now, you know a bit about our Heros, but we need to talk to NPCs called Maven and SpringIDE before starting!
2. Environment Configuration
For talking to Maven and SpringIDE NPCs, we need to configure our environment. Firstly if you don't have MySQL server, try to download it from here and install it, it's easy.
After finishing configuration, we download a Ragnarok database script from eAthena private server:
Now type:
mysql -uroot
if you have not set any password to “root” user, or:
mysql -uroot -p
if you have set a password to mysql “root” user.
Finally we import data into the database by using this script:
CREATE DATABASE Ragnarok;
USE Ragnarok;
\. [your-path]/mob_db.sql
\. [your-path]/item_db.sql
After installing, configuring MySQL and importing Ragnarok data, we install Maven by following these steps (don't miss this part so that you don't need to come back later).
Now, this is the time to configure Maven in Eclipse. Eclipse! Why? This is a great IDE we can find because many plug-ins can facilitate in developing (I'm not an Eclipse fun boy, I'm using it because I'm a bit of a cheater =) ), okay if you don't have Eclipse JEE, try to download it from here.
After we try to install this plug-in in Eclipse IDE:
- Select Help > Install New Software. This should display the "Install" dialog.
- Paste the Update Site URL (http://m2eclipse.sonatype.org/sites/m2e) into the field named "Work with:" and press Enter. Pressing Enter should cause Eclipse to update the list of available plugins and components.
- Choose the component listed under m2eclipse: "Maven Integration for Eclipse (Required)".
- Click Next. Eclipse will then check to see if there are any issues which would prevent a successful installation.
- Click Next and agree to the terms of the Eclipse Public License v1.0.
- Click Finish to begin the installation process. Eclipse will then download and install the necessary components.
- Once the installation process is finished, Eclipse will ask you if you want to restart the IDE. Sonatype strongly recommends that you restart your IDE after installing m2eclipse.
We also install SpringIDE from here (similar steps).
Very nice, now we create our project just for showing why we have used Maven plug-ins in this article – and we stop here – in Eclipse we create a new Maven project, we call it “ragnarok-spring-hibernate” as you can see here:
Next, we check “Create a simple project (skip archtype selection)”:
Next, in Group Id: “ro.springhibernate”, and also Artifact: “ragnarok-spring-hibernate”:
If the project created is successful, we convert it to a spring project, don't worry it's easy! Very easy! Perhaps you remember SpringIDE, it's time to use it. By simply right clicking on the project, we find at the bottom of context menu “Spring tools” and we click in “Add Spring Project Nature”!
Ouf, finally we paste this code in POM.xml file and Maven downloads all the needed libraries without any efforts or basic knowledge about them. (Just copy paste it before </project> in POM file.)
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.6.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.3.0.GA</version>
</dependency>
<dependency>
<groupId>org.apache.pivot</groupId>
<artifactId>pivot-core</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.apache.pivot</groupId>
<artifactId>pivot-wtk</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.apache.pivot</groupId>
<artifactId>pivot-wtk-terra</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.4.2</version>
</dependency>
</dependencies>
“First Quest Completed!”
2.0 - If You Have To Troubleshoot!
In many books or tutorials this part has been ignored, and the reader is discouraged too, just because he does not want to be called "n00b", be "n00b". The first-time is not the end of the world =). Okay we are back.
If you are shocked by a very gentle-error after restarting Eclipse “The Maven integration requires ...”.
This is easy to fix, just create “.BAT” file if you use Windows -- and you're lazy -- you don't want to repeat this step every time you open your Eclipse, try to write this code in BAT file and launch it:
eclipse.exe -vm "path to your JDK or JRE/bin"
Example:
eclipse -vm "C:\Program Files\Java\jdk1.6.0_13\bin"
If you have any problem, troubleshoot with Maven dependencies (downloaded libraries) or libraries not found! At this moment you need to do it by yourself, try to search missed “jars” in http://mirrors.ibiblio.org/pub/mirrors/maven2/ or any Maven repository, download 3 files:
- your-missed-jar.JAR
- your-missed-jar.JAR.MD5
- your-missed-jar.JAR.SHA1
and install them manually. Finally try to restart Eclipse or save POM.xml file for automatically checking:
mvn install:install-file -Dfile=your-missed-jar.JAR -DgroupId=org.some.group
-DartifactId=your-artifact -Dversion=jar-version -Dpackaging=jar
Just wait! Where can I find DgroupId
(GroupId
), DartifactId
(ArtifactId
), Dversion
(Version
)?
Excellent question, just look in the Eclipse Console and you will find all the needed information!
3. Simple Application
Our simple application has code named “RoManager
” for managing as you can notice mobs (Monsters) and items, use case diagram:
Okay! We have an understanding of the application objective! But how does the system work?
RoManager
basically uses Pivot for creating a user interfaces UI (Views Java classes for binding WTKX files), Spring for configuration and creating beans to be used by Controllers (controllers is a Listener and we explain it in detail later).
Wait wait wait, what's the role of “roempire.com”?
Oh! really you want to know it? Euh, this a tiny white hack for retrieving mobs and items images from RoEmpire on-line database. We don't need to download Ragnarok client (+3Gbytes) and extract it just for getting spirits!? And that stuff is a bonus in the article, you can use it in many domains! Ops as web-services, RSS, etc.
4. Application Architecture (MVC)
In this article, we have a similar architecture as ASP.NET MVC. See image of explorer, and NOT similar functionality, am I a bad guy?
I don't know, but, I just want to organize application code and have found an easy architecture, it's not a standard organization? Let's compare Our MVC Architecture and Microsoft! -- default project --
Our MVC Architecture | Microsoft ASP.NET MVC Architecture |
| |
Our architecture is better than that of Microsoft! This is because it a Desktop MVC, not Web MVC.
We have a folder source “models”. This folder contains only all mapping classes POJO and DAO, other stuff is not allowed here.
“controllers” source folder contains just controllers (Listeners
classes) grouping by package, for every package name is a name of “View
” class, for grouping a controller by its Java UI class (View) as:
- View name (
RoManager
) - In controllers source folder, a package called “
romanager
” contains all controllers for View RoManager
.
And “views” source folder contains all Java UI classes only! Don't include WTKX files.
But where are the WTKX files?
WTKX files are not source code -- they can't be compiled -- for this reason I've moved them from “views” source folder to “resources” folder. Personally I like separating source files, they can be compiled as Java from text file such as WTKX.
Finally a “java” source folder contains all new developed stuff as “Linker
” class or others.
“The key has been found!”
5. Making “Magical Stuff”
“Welcome to Niflheim.”
No worries if you're not understanding, are confused, or you've to troubleshoot with this section in the article, if you are not interested in Java Reflection and its techniques as Inversion of control (IoC). You can skip it easily and not see what are the content of class Linker
, just use it.
But, if you're interested, you can see after reading this article, another high-level and what we can do with a simple Java Reflection library.
The “Magical stuff”, a Linker
class has two objectives:
- Separation
Listeners
classes (we call them controllers) from Pivot Java UI Class (class we bind components, called Views in this article). - Offering an easy changing of controllers without re-compiling source code.
– The Linker work similar to that of Spring –
Read from configuration file and add to specific components its Controllers
, you're confused? No problem, open your big eyes.
Firstly, see the Java source code here and don't play with other's examples!
25
26 pushButton.getButtonPressListeners().add(new ButtonPressListener() {
27 @Override
28 public void buttonPressed(Button button) {
29 Alert.alert(MessageType.INFO, "You clicked me!", window);
30 }
31 });
For us [1] Listener = Controller
and [2] Listener = ButtonPressListener
.
From [1] and [2], we can notice that Controller
is included in Java UI class and this is Contrary to the Theory of our Architecture. For this reason, Linker
has been created for linking a separated “Listeners
” to binded components by using a configuration file.
Realizing a separated Controllers
from Views
.
First method called ''bind
' is simple and is used in Pivot tutorials. We just simplified it here!
public static void bind(Object obj, String ui) throws IOException,
SerializationException
{
WTKXSerializer serializer = new WTKXSerializer();
serializer.readObject( new Linker().resource( ui ) );
serializer.bind(obj);
}
The second method called “link
” is for linking controllers
to “components
”. Notice we can link many controllers
to one component
.
@SuppressWarnings({ "unchecked" })
public static void link(Object obj) throws ParserConfigurationException,
SAXException, IOException, XPathExpressionException,
ClassNotFoundException, SecurityException, NoSuchMethodException,
IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException, NoSuchFieldException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse( new Linker().resource("controllers.xml") );
XPathFactory xfactory = XPathFactory.newInstance();
XPath xpath = xfactory.newXPath();
XPathExpression xexpression = xpath.compile("//Configuration/View
[@name='" + obj.getClass().getSimpleName() + "']/Controller");
NodeList result = (NodeList) xexpression.evaluate(document,
XPathConstants.NODESET);
for( int x = 0 ; x < result.getLength() ; x++ )
{
String fieldName =
result.item( x ).getAttributes().getNamedItem("field").getNodeValue();
String className =
result.item( x ).getAttributes().getNamedItem("class").getNodeValue();
String eventName =
result.item( x ).getAttributes().getNamedItem("event").getNodeValue();
String eventPckg =
result.item( x ).getAttributes().getNamedItem
("eventPackage").getNodeValue();
eventPckg = eventPckg != null && !eventPckg.isEmpty() ?
eventPckg : "org.apache.pivot.wtk";
Object classInstance = null;
{
Class clazz = Class.forName("controller." +
obj.getClass().getSimpleName().toLowerCase() +
"." + className + "Controller");
Constructor ctr = clazz.getConstructor
( new Class[]{Object.class} );
classInstance = ctr.newInstance(new Object[]{ obj });
}
Object fieldObject = null ;
{
Field field = obj.getClass().getDeclaredField( fieldName );
field.setAccessible( true );
fieldObject = field.get(obj);
}
Object lisenter = null;
{
Method method = fieldObject.getClass().getMethod
( "get" + eventName + "Listeners" , new Class[]{});
lisenter = method.invoke( fieldObject , new Object[]{});
}
{
Method method = lisenter.getClass().getMethod
("add", new Class[]{Object.class} );
method.invoke( lisenter , new Object[]{classInstance} );
}
}
}
– Why don't we use Spring? We can do similar work if we are using it! –
To be continued in “8 – Linking with magical stuff 'Controller'."
6. Mapping! POJO and DAO “Model”
We don't discuss here about how to configure Spring and Hibernate. You can download source and view applicationContext.xml, hibernate.cfg.xml and jdbc.properties files.
In our case, a POJO is easy, we don't have a complex database schema, no many-to-many, no one-to-many relationships, just individual tables “mob_db
” and “item_db
”.
Q: But we use all these columns just for demonstration?
A: No! We use just interesting columns such as “ID
”, “Name
”!
Q: We discuss about “mobs
” and “items
”, maybe they have similar function?
A: Yes! As you can see in Use Case “mob
” and “item
” have similar functions, we discuss only about “mobs
” for demonstration.
Q: What type of mapping do we use?
A: Annotations is easy.
Q: It's hard to understanding this section from the article?
A: Ops! Secret.
We create a class named “Mob
” that contains only the interested columns:
ID
(e.g.: 1109) Sprite
(e.g.: DEVIRUCHI) kName
(e.g.: Deviruchi) LV
(e.g.: 46) HP
(e.g.: 6666) SP
(e.g.: 0) Race
(e.g.: Demon)
(Deviruchi is my preferred pet (>_<)”! kawaii-desu ?!)
We create a DAO interface that contains 2 methods:
public interface MobDAO
{
public List<Mob> getList();
public boolean edit( Mob mob );
}
You can see the implementation of this interface in the source code.
7. Creating Pivot WTKX “View”
If you're here! and not discouraged yet, you're really trapped by curiosity (^_^), and I have for you two news, what do you want first - “Good” or “Bad”?!
Okay I choose “bad” News! Currently – we can't cheat in Pivot and we can't use any bot or AI for Exp – I mean currently we don't have any syntax colorization, intellisense, wizards, drag-and-drop, etc. You do everything using your favorite text editor. Look here.
“Good” News! Pivot UI is very easy and clear. You can become a guru or you can find others' ideas, to revolutionary them, because you know “what you want” unlike people using DND (drag and drop) and wizards. You want to try? Don't fear! Pivot team has planned a GUI Builder, see this link.
But we are cheaters, we add to WTKX file “.xml” because we have a syntax colorization in Eclipse!
As I've mentioned, WTKX files is located in the resource folder, and we have two files:
- romanager/ui.wtkx.xml for
RoManager View
- romanager/mobs/ui.wtkx.xml for
EditMob View
You discover WTKX file for RoManager
in the source code, but I'll show you EditMob
WTKX file here:
<Dialog wtkx:id="dialogEditMob" title="Edit Mob!"
xmlns:wtkx="http://pivot.apache.org/wtkx"
xmlns="org.apache.pivot.wtk">
<content>
<BoxPane>
<Form wtkx:id="formEditMobs">
<sections>
<Form.Section>
<Label wtkx:id="labelID" Form.label="ID" textKey="id"/>
<Label wtkx:id="labelSprite" Form.label="Sprite"
textKey="sprite"/>
<TextInput wtkx:id="textName" Form.label="Name"
textKey="name"/>
<TextInput wtkx:id="textLevel" Form.label="Level"
textKey="level"/>
<TextInput wtkx:id="textHP" Form.label="HP" textKey="hp"/>
<TextInput wtkx:id="textSP" Form.label="SP" textKey="sp"/>
<TextInput wtkx:id="textRace" Form.label="Race"
textKey="race"/>
<Separator/>
<Label wtkx:id="labelMessage"/>
</Form.Section>
</sections>
</Form>
<BoxPane>
<PushButton wtkx:id="btnSave" buttonData="Save"/>
<PushButton wtkx:id="btnClose" buttonData="Close"/>
</BoxPane>
</BoxPane>
</content>
</Dialog>
and this is a Java UI class:
public class EditMob
{
@WTKX private Dialog dialogEditMob = null;
@WTKX private Form formEditMobs = null;
@WTKX private Label labelID = null;
@WTKX private Label labelSprite = null;
@WTKX private TextInput textName = null;
@WTKX private TextInput textLevel = null;
@WTKX private TextInput textHP = null;
@WTKX private TextInput textSP = null;
@WTKX private TextInput textRace = null;
@WTKX private PushButton btnSave = null;
@WTKX private PushButton btnClose = null;
@WTKX private Label labelMessage = null;
public EditMob() throws Exception
{
Linker.bind(this, "romanager/mobs/ui.wtkx.xml");
Linker.link( this );
}
public Dialog getDialogEditMob() {
return dialogEditMob;
}
public Form getFormEditMobs() {
return formEditMobs;
}
public Label getLabelID() {
return labelID;
}
public Label getLabelSprite() {
return labelSprite;
}
public TextInput getTextName() {
return textName;
}
public TextInput getTextLevel() {
return textLevel;
}
public TextInput getTextHP() {
return textHP;
}
public TextInput getTextSP() {
return textSP;
}
public TextInput getTextRace() {
return textRace;
}
public PushButton getBtnSave() {
return btnSave;
}
public PushButton getBtnClose() {
return btnClose;
}
public Label getLabelMessage() {
return labelMessage;
}
}
Easy?
8. Linking with Magical Stuff “Controller”
Continuing …! The controllers
have been configured automatically by the Linker
class, from the file located in resource folder called “controllers.xml”, I've created a DTD file for intellisense:
DTD file a “linker.dtd” file source code:
<!ELEMENT Configuration (View*)>
<!ELEMENT View (Controller*)>
<!ELEMENT Controller EMPTY >
<!ATTLIST View name CDATA #REQUIRED>
<!ATTLIST Controller field CDATA #REQUIRED>
<!ATTLIST Controller class CDATA #REQUIRED>
<!ATTLIST Controller event CDATA #REQUIRED>
<!ATTLIST Controller eventPackage CDATA "">
for creating a controller! For any component in Java UI class, it is mandatory to implement a Listener
interface, and add a constructor with one parameter: Object
, for passing a View
(Java UI class) object as you can see here:
public class CloseDialogController implements ButtonPressListener
{
private EditMob view = null ;
public CloseDialogController( Object view )
{
this.view = (EditMob) view;
}
public void buttonPressed(Button button) {
this.view.getDialogEditMob().close();
}
}
Finally just by adding controller (called bean in Spring) in “controllers.xml” without “Controller” in name, the controller CloseDialog
has automatically linked (injected in Spring) in its component
:
<Controller event="ButtonPress"
class="adrabi.codeproject.controllers.editmob.CloseDialog" field="btnClose"/>
Magic?
Here a full controllers.xml source:
<!DOCTYPE Configuration SYSTEM "linker.dtd" >
<Configuration>
<View name="RoManager">
<Controller event="ButtonPress"
class="adrabi.codeproject.controllers.romanager.RefreshMobs"
field="btnRefreshMob"/>
<Controller event="ButtonPress"
class="adrabi.codeproject.controllers.romanager.EditMob"
field="btnEditMob"/>
<Controller event="TableViewSort"
class="adrabi.codeproject.controllers.romanager.MobsSort"
field="tableMobs"/>
<Controller event="TableViewSelection"
class="adrabi.codeproject.controllers.romanager.ShowDetails"
field="tableMobs"/>
<Controller event="ImageView"
class="adrabi.codeproject.controllers.romanager.ImageMobLoad"
field="imageMob"/>
</View>
<View name="EditMob">
<Controller event="ButtonPress"
class="adrabi.codeproject.controllers.editmob.CloseDialog"
field="btnClose"/>
<Controller event="ButtonPress"
class="adrabi.codeproject.controllers.editmob.SaveMob"
field="btnSave"/>
</View>
</Configuration>
“Final Quest completed.”
9. Summary
Big secret, I'm an ASP.NET developer =)! JavaEE, Spring, Hibernate are new to me. I've starting this article for encouraging me to learn a bit about JEE, by using hikikomori/nolife style to be funny for other newbies interested in JEE! Now you know that neither Adobe nor Microsoft can create RIA Frameworks, Apache also has entered in RIA challenge by Pivot.
- Pivot is a RIA made in Apache, by using Java technology and XML.
- Spring, evil framework provide a lot of support for other frameworks such as Hibernate.
- Hibernate, a popular Persistence/ORM framework for Java.
Go to the source and complete “items
” managing such as “mobs
”!
“Game Over!”
Thank you very much for reading, and for your comments, votes, suggestion and corrections.
10. History
- 28th March, 2010: Initial version