Appfuse – quick start guide for newbies.

Appfuse

Add classes to initial project creation

2/12/2010

Overview:

You have done the QuickStart to see if you can get everything to work. This article assumes you DID indeed get the initial project working. You’re excited and want to “add something” to that project and begin working on your own. You need to read through this with a clear head because there is a gotcha once you get past adding ONE java class file. Not sure why but there is a fix.

Ok here’s the scoop.

Use the videos for the tutorial. They’re up to date. The other tutorials never worked for me.

This is the writeup translating the videos into text. I did not add ANYTHING to this except a little clarification for us newbies.

All we’re doing here is generating CRUD which is not normally what is needed in a real app. However, we do this here to get a feel for how all these frameworks work.

You want to create a Plain Old Java Object (POJO). This is a simply a java class file. One Object per file.

I use cygwin for development on Windows. I need to resetup my Linux box. I will try to write clarifying statements so you can figure out what I am doing.

So let’s say we create a Java Class called Person. Why? Because I need one in my project.

My app name is tree. My company is Joroto.com.

So the path to my source is:

./tree/src/main/java/com/joroto

We’re going to create this Person.java file in a NEW directory called model.

So you now have a directory structure

./tree/src/main/java/com/joroto/model

Step 1 of a “Template for working in Appfuse”. When I say execute Step 1 again, do this with a different Java Class (just trying to be clear).

Create a Person.java file in ./tree/src/main/java/com/joroto/model

Here’s mine so you can first test that this works for you, then extend it. There is a note about renaming files and objects, later in this tutorial. READ THOSE NOTES, maybe even before you do this here. Nothing devastating, but important just the same.

package com.joroto.model;

import org.appfuse.model.BaseObject;

import javax.persistence.*;

import org.compass.annotations.Searchable;

import org.compass.annotations.SearchableComponent;

import org.compass.annotations.SearchableId;

import org.compass.annotations.SearchableProperty;

import java.sql.Timestamp;

// Entity tells the processing framework that you want this object to be backed by a database.

@Entity @Table(name=”person”)

// The searchable is to help identify tables that need a search engine, are highly searched. Might be a “Trails-hibernate” module for search engine like capability.

// http://docs.codehaus.org/display/TRAILS/Querying+entities+and+full-text+search

@Searchable

public class Person extends BaseObject /* implements java.io.Serializable */ {

private Long uid;

private String title; // Mr., Dr. etc.

private String fName; // First name

private String mName; // Anything other than first and last name

private String lName; // Last name

@Override

public String toString() {

String s = new String();

if (mName.length() > 0) {

s=String.format(“%s %s %s %s”, title, fName, mName, lName);

} else {

s=String.format(“%s %s %s”, title, fName, lName);

} // if-else

return s;

}

@Override

public int hashCode() {

throw new UnsupportedOperationException(“Not supported yet.”);

}

@Override

@SuppressWarnings(“EqualsWhichDoesntCheckParameterClass”)

public boolean equals(Object o) {

Person p = (Person)o;

return(p.uid == this.uid);

} // equals

// Getters and Setters

// Indicates that this is the primary key for this event

@Id@GeneratedValue(strategy=GenerationType.AUTO)

@Column(name=”uid”)

public Long getUid() {

return uid;

}

@Column(name=”uid”)

public void setUid(Long uid) {

this.uid = uid;

}

@Column(name=”title”, length=20)

public String getTitle() {

return title;

}

public void setTitle(String s) {

this.title = s;

}

@Column(name=”firstname”, length=100)

public String getFirstName() {

return fName;

}

public void setFirstName(String s) {

this.fName = s;

}

@Column(name=”middlename”, length=100)

public String getMiddleName() {

return mName;

}

public void setMiddleName(String s) {

this.mName = s;

}

@Column(name=”lastname”, length=100)

public String getLastName() {

return lName;

}

public void setLastName(String s) {

this.lName = s;

}

}

The statements with the @ signs are annotations that are used when this code generates the database table. The database table (in Hibernate) will store the information the flows into and out of this class.

That’s all we need to do in this file so save it.

We need to tell the system that we’ve created this and it needs to be backed by hibernate. Open the following file (it is already in the directory structure from your initial generation of the project.

./tree/src/main/resources/hibernate.cfg.xml

Add a new line at line 8 below the other <mapping class…> members.

Add the following line to that new line.

<mapping class=”com.joroto.model.Person”/>

Save and close that file.

You’re ready for the cool automation that Matt and his Magical Minions dreamed up.

In the ./tree directory execute the following command

mvn appfuse:gen -Dentity=Person

If the build is not successful, make a very basic Class file like I did up there. We WILL be able to regenerate the files with more of the Class attributes in it.

After a successful build execute the next command (Matt thinks executing these two commands is “too much” and will release a future version combining the two. However, just “think” of all the work these two command are saving us and you should be sending the guy some percentage of your commercial profits)

mvn appfuse:install -Dentity=Person

And then execute

mvn test

It will work.

mvn jetty:run-war

Point your browser to

Localhost:8080

Go back to the step 1 of this tutorial and enter a new and different Java class. When you get to the mvn test, you’ll notice that it fails the test classes. The Person class is flagged. Matt (not me) to the rescue in his MarkMail app. On the appfuse home, click on Project Information, Mailing Lists and then MarkMail. Enter the error about creating the bean and up pops his answer. You’re asking “where is the error? The console displays where to go, but for clarity go to

./tree/target/surefire-reports

Any .txt file that is not 1k is telling you about the test errors.

Here is Matt’s fix for the problem, then I’ll explain:

Open the file

./tree/src/main/webapp/WEB-INF/applicationContext.xml

There are now three things that need to be done to the file. As you add Classes for CRUD you’ll need to edit its Bean element after you do the mvn appfuse:install -Dentity=Person above.

Add the <context:component-scan base-package=”org.appfuse”/> element.

AND you have to add the element <property name=”sessionFactory” ref=”sessionFactory”/> to each bean. One for the personManager bean and once for (in my case) teventManager bean. So the file now looks like this:

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xmlns:context=”http://www.springframework.org/schema/context”

xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

default-lazy-init=”true”>

<!– Activates scanning of @Autowired –>

<context:annotation-config/>

<!– Activates scanning of @Repository and @Service –>

<context:component-scan base-package=”com.joroto”/>

<context:component-scan base-package=”org.appfuse”/>

<!– Add new DAOs here –>

<!–PersonManager-START–>

<bean id=”personManager” class=”org.appfuse.service.impl.GenericManagerImpl”>

<constructor-arg>

<bean class=”org.appfuse.dao.hibernate.GenericDaoHibernate”>

<constructor-arg value=”com.joroto.model.Person”/>

<property name=”sessionFactory” ref=”sessionFactory”/>

</bean>

</constructor-arg>

</bean>

<!–PersonManager-END–>

<!–TeventManager-START–>

<bean id=”teventManager” class=”org.appfuse.service.impl.GenericManagerImpl”>

<constructor-arg>

<bean class=”org.appfuse.dao.hibernate.GenericDaoHibernate”>

<constructor-arg value=”com.joroto.model.Tevent”/>

<property name=”sessionFactory” ref=”sessionFactory”/>

</bean>

</constructor-arg>

</bean>

<!–TeventManager-END–>

<!– Add new Managers here –>

</beans>

Matt was right. This fixes the test errors and you’re off and running. The above file is generated during the gen and install command.

Notes:

mvn clean will clear out the target directory.

Renaming a class

Ok so you want to rename a Class. You need to search the ./tree/src/ directory for your class and all variants and clear them out.

First fix the ./tree/src/main/resources/hibernate.cfg.xml file

Then rename your class, any references inside the file, and finally the name of your class file.

In this case I’m going to rename the Tevent class (which was my second class added. I did not post that above) to Event. So I rename the @Table, the Class name is now Event. Inside the Class is a reference to Tevent that is now Event. Save your class in the

./tree/src/main/java/com/joroto/model directory.

Run the following command from the command line.

mvn clean command to get rid of the target files.

If in cygwin, issue the find command find . -name “[tT]event*” to see all of the files leftover that need to be deleted. In windows search for the name of the OLD class. Delete all those files. In cygwin do this:

find . -name “[tT]event*” | xargs rm -f

Let’s generate the files and test them by running the commands on the command line:

mvn appfuse:gen -Dentity=Event

mvn appfuse:install -Dentity=Event

Edit the file

./tree/src/main/webapp/WEB-INF/applicationContext.xml

Delete the old Class reference for the bean. You have to take out the whole <bean ….> to </bean>

Add the <property … sessionFactory line from above. Save the file. Then enter on the command line:

mvn test

Should be good to go. Lets check. At the command line:

mvn jetty:run-war

Point your browser to localhost:8080

You’ll notice that ALL of the Classes are on the tab bar. You’ll need to clean out the jsp files for the classes that don’t exist. SO. . . Let’s look for all of these references. Change directory to the ./tree/src directory. Run the cygwin command:

grep -lri tevent main/*

This will list the files that need to be cleaned up. I don’t know how to do this automatically, so let’s edit each file looking for the reference to the old class name.

My list is (Use this as a learning experience as to how to modify your web application. These are the pages and values that go to the final html that is output):

main/resources/ApplicationResources.properties - You’ll see the section for your old class. Pretty easy to delete it.

main/resources/struts.xml - You’ll see the section for your old class. Pretty easy to delete it.

main/webapp/common/menu.jsp – You’ll see the section for your old class. Pretty easy to delete it.

main/webapp/WEB-INF/menu-config.xml – You’ll see the section for your old class. Pretty easy to delete it.

Now edit these files:

test/resources/sample-data.xml – You’ll see the section for your old class. Pretty easy to delete it.

test/resources/web-tests.xml – You’ll see the depends clause. Now each time you gen a Class you’ll see it added here. So if you mess up and keep gen’ing the Person class, it will have that many Person entries here. Then down further in the file you’ll see the section for that your old class created. Delete that section.

Change directory back to ./tree

At the command line run

mvn clean

mvn test

The test should be successful. If not, then recheck your editing. Mine always worked. However, your editing is definitely where the problem lies at this time since you’ve already tested the New class you generated above.

Finally, to make sure the old class “stuff” no longer displays in the web app. Execute from the command line:

mvn jetty:run-war

I’m done here. Hopefully this gets you quickly up to speed on this cool stuff that Matt and his Magic Minions create. Kudos to the the AppFuse team.

  • Share/Bookmark
This entry was posted in Miscellaneous Apps and Services and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>