- First, download Seam from here
- Unzip to a folder of your choosing
- Run bin\forge
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
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
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 + "]";
}
}
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;
}
}
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>
...
<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>
...
<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>
...
<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!
6 comments:
Richard, another awesome post!
I might add that you can put richfaces in the pom using forge as well:
$ project add-depenency org.richfaces.ui:richfaces-ui:3.3.3.Final
$ project add-depenency org.richfaces.framework::3.3.3.Final
Nice Article!
Another way to add RichFaces to your forge app is using my RichFaces plugin for Forge:
forge git-plugin git://github.com/bleathem/richfaces-forge-plugin.git
and the run:
richfaces setup
Thanks guys. Blog post now updated. Wow, Forge is really moving fast!
Regards,
Richard.
This is not exactly a nice article. Those who work in J2EE/Seam/JSF projects, they will not appreciate some mechanical/auto-generated code. Forge forces you to use Metawidget; Metawidget generates mechanical code; for very simple Hello-World type projects, metawidget is fine, but not for Real life projects. Forge should have the flexibility to integrate/use Richfaces, seam directly .. etc, and not by going through Metawidget.
Christy,
To be fair, we've spent a lot of time making sure Metawidget *is* fine for Real Life projects. And lots of Real Life projects use it in production. If there is an area where Metawidget doesn't work for you, please explain it on the Metawidget forums. I'd love to improve it for you.
Having said that, Forge is not tied to Metawidget. We are looking to make Forge output static JSF tags in the near future.
Regards,
Richard.
FYI: outputting static JSF tags in JBoss Forge has now been released:
http://blog.kennardconsulting.com/2011/12/you-cant-spell-forge-without-metawidget.html
Post a Comment