JBoss have just released
Seam 3.0.0.Final, which includes Alpha 3 of Seam Forge. So I thought I'd improve my
previous blog entry:
- First, download Seam from here
- Unzip to a folder of your choosing
- Run bin\forge
Type the following commands and press
ENTER after each one. Accept any defaults you are prompted for, and remember to use
TAB and
UP ARROW autocomplete:
new-project --named MyApp --topLevelPackage com.myapp
persistence setup --provider HIBERNATE --container JBOSS_AS6
new-entity --named Person
new-field string --named firstname
new-field string --named surname
new-field int --named age
new-field string --named notes
new-field custom --named homeAddress
[type=The qualified Class to be used as this field's type (of type java.lang.String)]: com.myapp.Address
new-field custom --named workAddress
[type=The qualified Class to be used as this field's type (of type java.lang.String)]: com.myapp.Address
new-entity --named Address
new-field string --named street
new-field string --named suburb
new-field string --named state
new-field string --named postcode
scaffold from-entity com.myapp.domain.Person.java
exit
Next:
- Open Eclipse (with m2eclipse installed)
- Choose File > Import > Existing Maven Projects and import the pom.xml at \seam-3.0.0.Final\forge\MyApp\pom.xml
- Right click the pom.xml and choose Run As > Maven package
- Take the WAR it generates under target/MyApp-1.0.0-SNAPSHOT.war and deploy it under JBoss AS 6.0.0.Final
Open your browser at
http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf:
Now, let's play around a bit! These are things that soon Forge will be able to do for you, but for now edit
Person.java and add the lines in bold:
package com.myapp.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Version;
import org.metawidget.inspector.annotation.UiComesAfter;
import org.metawidget.inspector.annotation.UiSection;
@Entity
public class Person
implements java.io.Serializable {
@Id
private @GeneratedValue( strategy = GenerationType.AUTO )
@Column( name = "id", updatable = false, nullable = false )
long id = 0;
@Version
private @Column( name = "version" )
int version = 0;
public long getId() {
return this.id;
}
public void setId( final long id ) {
this.id = id;
}
public int getVersion() {
return this.version;
}
public void setVersion( final int version ) {
this.version = version;
}
@Column
private String firstname;
public String getFirstname() {
return this.firstname;
}
public void setFirstname( final String firstname ) {
this.firstname = firstname;
}
@Column
private String surname;
@UiComesAfter( "firstname" )
public String getSurname() {
return this.surname;
}
public void setSurname( final String surname ) {
this.surname = surname;
}
@Column
private int age;
@UiComesAfter( "surname" )
public int getAge() {
return this.age;
}
public void setAge( final int age ) {
this.age = age;
}
@Column
private String notes;
@UiComesAfter( "workAddress" )
@Lob
@UiSection( "Other" )
public String getNotes() {
return this.notes;
}
public void setNotes( final String notes ) {
this.notes = notes;
}
@Column
private Address homeAddress = new Address();
@UiComesAfter( "age" )
@UiSection( "Details" )
public Address getHomeAddress() {
return this.homeAddress;
}
public void setHomeAddress( final Address homeAddress ) {
this.homeAddress = homeAddress;
}
@Column
private Address workAddress = new Address();
@UiComesAfter( "homeAddress" )
public Address getWorkAddress() {
return this.workAddress;
}
public void setWorkAddress( final Address workAddress ) {
this.workAddress = workAddress;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "[" + id + ", " + version + ", " + firstname + ", " + surname + ", " + age + ", " + notes + ", " + homeAddress + ", " + workAddress + "]";
}
}
Similarly for
Address.java:
package com.myapp.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Version;
import org.metawidget.inspector.annotation.UiComesAfter;
@Entity
public class Address
implements java.io.Serializable {
@Id
private @GeneratedValue( strategy = GenerationType.AUTO )
@Column( name = "id", updatable = false, nullable = false )
long id = 0;
@Version
private @Column( name = "version" )
int version = 0;
public long getId() {
return this.id;
}
public void setId( final long id ) {
this.id = id;
}
public int getVersion() {
return this.version;
}
public void setVersion( final int version ) {
this.version = version;
}
@Column
private String street;
public String getStreet() {
return this.street;
}
public void setStreet( final String street ) {
this.street = street;
}
@Column
private String suburb;
@UiComesAfter( "street" )
public String getSuburb() {
return this.suburb;
}
public void setSuburb( final String suburb ) {
this.suburb = suburb;
}
@Column
private String state;
@UiComesAfter( "suburb" )
public String getState() {
return this.state;
}
public void setState( final String state ) {
this.state = state;
}
@Column
private String postcode;
@UiComesAfter( "state" )
public String getPostcode() {
return this.postcode;
}
public void setPostcode( final String postcode ) {
this.postcode = postcode;
}
}
Then tell
metawidget.xml we'd like to use
RichFaces:
<htmlMetawidget xmlns="java:org.metawidget.faces.component.html">
...
<widgetBuilder>
<compositeWidgetBuilder xmlns="java:org.metawidget.widgetbuilder.composite" config="CompositeWidgetBuilderConfig">
<widgetBuilders>
<array>
<overriddenWidgetBuilder xmlns="java:org.metawidget.faces.component.widgetbuilder"/>
<readOnlyWidgetBuilder xmlns="java:org.metawidget.faces.component.html.widgetbuilder"/>
<richFacesWidgetBuilder xmlns="java:org.metawidget.faces.component.html.widgetbuilder.richfaces"/>
<htmlWidgetBuilder xmlns="java:org.metawidget.faces.component.html.widgetbuilder" config="HtmlWidgetBuilderConfig"/>
</array>
</widgetBuilders>
</compositeWidgetBuilder>
</widgetBuilder>
<layout>
<tabPanelLayoutDecorator xmlns="java:org.metawidget.faces.component.html.layout.richfaces" config="TabPanelLayoutDecoratorConfig">
<layout>
<simpleLayout xmlns="java:org.metawidget.faces.component.layout"/>
</layout>
</tabPanelLayoutDecorator>
</layout>
</htmlMetawidget>
And tell
web.xml the same
(update: this can be done using the richfaces-forge-plugin, see the comments below):
<web-app >
...
<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>richfaces</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
</web-app>
And finally
pom.xml too
(update: this can be done using add-dependency, see the comments below):
<dependencies>
...
<dependency>
<groupId>org.richfaces.ui</groupId>
<artifactId>richfaces-ui</artifactId>
<version>3.3.3.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.richfaces.framework</groupId>
<artifactId>richfaces-impl</artifactId>
<version>3.3.3.Final</version>
<scope>compile</scope>
</dependency>
</dependencies>
Then redeploy your app and hit
http://localhost:8080/MyApp-1.0.0-SNAPSHOT/scaffold/person/list.jsf again:
Of course, Seam Forge is still in alpha so not everything works yet. But hopefully this has whetted your appetite for things to come!