Showing posts with label Seam Forge. Show all posts
Showing posts with label Seam Forge. Show all posts

Friday, December 23, 2011

Forge and Metawidget Discussed On JBoss Community Asylum

Metawidget, and the work we're doing with the JBoss Forge team, has gotten a nice mention on the latest episode of the JBoss Community Asylum podcast. Here's an excerpt (taken from 35m.22s):

Max: "Right now if you download Forge right now, you get a JSF Metawidget thing"

Lincoln: "Right you get a default scaffolding provider we call them, and that one right now is using - like you said - JSF and Metawidget which we're actually working on the next version of, so that... right now when you run the scaffold it basically looks at your database objects, your JPA objects, it runs through them all and generates a bunch of view files for the Create, Read, Update, Delete operations. You know, a simple interface."

Max: "So this is kind of like what seam-gen did before, right?"

Lincoln: "Right. Kind of like that. And when you look at the output of the scaffold that you would download, maybe from Beta 3, you will see this Metawidget tag and Metawidget is..."

Max: "Yeah why don't you just tell what Metawidget is?"

Lincoln: "Metawidget is a really cool framework actually, it..."

Emmanuel: "We should interview... er... forgot his name..."

Max: "Richard? Richard something? Kennard"

Lincoln: "Richard Kennard"

Max: "Yeah Kennard"

Lincoln: "...it's a really cool framework for, basically you just point this tag at an Object or a bean and it runs through that bean and looks at all the properties and builds up an interface that shows up on the page."

Max: "Yeah, and in your JSF you just have one [line] and say this is the bean I want to do and it builds the UI. And it does it for... er... Swing, and..."

Lincoln: "You can do Swing, you can do GWT, you can do JavaFX I think. Lots of stuff."

Max: "So actually it is pretty powerful, but it's not..."

Lincoln: "The problem is then you've got this tag in there and it's... if you want to customize that then you're learning the Metawidget framework. And so what we are doing right now actually is we're customizing Metawidget so that, using the same inspection process that Metawidget provides, generate real code. Materializes it into real XML, real JSF pages. Then you can go in and modify those pages just like you would have done by yourself."


Listen to the full podcast here.

Monday, December 19, 2011

You Can't Spell Forge Without Metawidget

JBoss have just released Beta 4 of JBoss Forge. There are a host of new features in this release. Most exciting for me being the new UI scaffolding.

Scaffolding has been significantly rewritten to use a new static Metawidget. This allows Forge to output pure JSF tags, with no runtime dependencies on any non-Java EE libraries. The UI includes creating, updating, deleting, pagination and searching. It also supports one-to-many, many-to-many, many-to-one and one-to-one relationships:
The code it generates is very clean:

<h:panelGrid columnClasses="label,component,required" columns="3">
   <h:outputLabel for="customerBeanCustomerFirstName" value="First Name:"/>
   <h:panelGroup>
      <h:inputText id="customerBeanCustomerFirstName" value="#{customerBean.customer.firstName}"/>
      <h:message for="customerBeanCustomerFirstName" styleClass="error"/>
   </h:panelGroup>
   ...

Behind the scenes, Forge is still using the same Metawidget pipeline as before - the same Inspectors, WidgetBuilders, WidgetProcesors and Layouts. This means the scaffolding is pluggable to adapt to your needs - including custom UI libraries, custom layouts, even custom langauges (Ceylon, anyone?).

The new static Metawidget is also used to generate Java code for the JSF backing beans. Again using WidgetBuilders and outputting very clean code:

String firstName = this.search.getFirstName();
if (firstName != null && !"".equals(firstName)) {
   predicatesList.add(builder.like(root.<String>get("firstName"), '%' + firstName + '%'));
}
String lastName = this.search.getLastName();
if (lastName != null && !"".equals(lastName)) {
   predicatesList.add(builder.like(root.<String>get("lastName"), '%' + lastName + '%'));
}

Please give it a try!
  • Download Forge Beta4

  • Install it

  • Run it

  • Copy and execute this command:
    $ run-url https://raw.github.com/forge/core/master/showcase/posale.fsh
For the lazy, I've uploaded the project that Forge generates. You can download it here.

Friday, April 1, 2011

Grokking Seam Forge: Part 3

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!

Wednesday, March 9, 2011

Grokking Seam Forge: Part 2

JBoss have just released Seam 3.0.0.CR2, which includes Alpha 2 of Seam Forge. It's an alpha, so expect pain, but let's take it for a spin!

  • First, download Seam Forge from here
  • Unzip to a folder of your choosing
  • Run bin\forge
Seam Forge is command-line driven, similar to Rails and Roo (though with loftier goals :). Type the sections in bold:

[no project] forge-1.0.0.Alpha2 $ new-project --named MyApp --topLevelPackage com.myapp
Use [/forge-1.0.0.Alpha2/MyApp] as project directory? [Y/n] y
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/resources/META-INF/forge.xml
***SUCCESS*** Created project [MyApp] in new working directory [/forge-1.0.0.Alpha2/MyApp]

[MyApp] MyApp $ persistence setup --provider HIBERNATE --container JBOSS_6
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/resources/META-INF/persistence.xml
***SUCCESS*** Installed [forge.spec.jpa] successfully.
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/resources/META-INF/persistence.xml

[MyApp] MyApp $ new-entity --named Person
In which package you'd like to create this @Entity, or enter for default: [com.myapp.domain]
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java
Created @Entity [com.myapp.domain.Person]
Picked up type : com.myapp.domain.Person

[MyApp] Person.java $ new-field string --fieldName firstName
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java
Added field to com.myapp.domain.Person: @Column private String firstName;
[MyApp] Person.java $ new-field string --fieldName surname
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java
Added field to com.myapp.domain.Person: @Column private String surname;
[MyApp] Person.java $ cd ..
[MyApp] domain $ scaffold from-entity com.myapp.domain.Person.java
The [forge.maven.WebResourceFacet] facet requires the following packaging type [war], but is currently [jar], would you like to change the packaging to [war]? (Note: this could break other plugins in your project.) [Y/n] y
Packaging updated to [war]
***SUCCESS*** Installed [forge.maven.WebResourceFacet] successfully.
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/beans.xml
***SUCCESS*** Installed [forge.spec.cdi] successfully.
The [forge.spec.jsf] facet depends on the following missing facets: [forge.spec.servlet]. Would you like to attempt installation of these facets as well? [Y/n] y
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/web.xml
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/index.html
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/faces-config.xml
***SUCCESS*** Installed [forge.spec.jsf] successfully.
***SUCCESS*** Scaffolding installed.
No scaffold type was provided, use Forge default? [Y/n] y
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/WEB-INF/beans.xml
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/org/jboss/seam/forge/persistence/DatasourceProducer.java
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/org/jboss/seam/forge/persistence/PersistenceUtil.java
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/resources/forge-template.xhtml
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/resources/forge.css
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/resources/favicon.ico
***INFO*** [/forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/domain/Person.java] File exists, re-run with `--overwrite` to replace existing files.
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/java/com/myapp/view/PersonBean.java
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/scaffold/person/view.xhtml
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/scaffold/person/create.xhtml
Wrote /forge-1.0.0.Alpha2/MyApp/src/main/webapp/scaffold/person/list.xhtml
***SUCCESS*** Generated UI for [com.myapp.domain.Person]

Next:

  • Open Eclipse (with m2eclipse installed)

  • Choose File > Import > Existing Maven Projects and import the pom.xml at \forge-1.0.0.Alpha2\MyApp\pom.xml
  • Edit src/main/resources/META-INF/persistence.xml and remove the line that says <non-jta-data-source/>
  • (a bug)
  • 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:
  • Click Create:
And that's it! Seam Forge has created a full web application for you, complete with JPA back-end and JSF front-end, without you having to write a single line of code. Of course there's much more to it than that, but hopefully this gives you a taste for what JBoss and the Seam Team are cooking up!

Monday, January 3, 2011

Grokking Seam Forge: Part 1

JBoss have just released Alpha 1 of Seam Forge, their framework for rapid-application development that includes Metawidget support.

You can read more about the release and how to use it here. After that, for those wanting to dive into the code (either out of curiosity or to start contributing) here's a step-by-step guide that may save some trial and error:

Install JBoss Tools

  • Download Eclipse 3.5 SR2 (just the 'Eclipse IDE for Java Developers' version)

  • Download JBoss Tools 3.1.GA

  • Unzip Eclipse, and run eclipse.exe

  • Select a workspace (I'd recommend starting a new one)

  • Use Help > Install New Software. Click Add then Archive (see screenshot):
  • Click OK

  • Check All JBoss Tools - 3.1.1. Click Next and Next again

  • Choose I accept the terms of the license agreements and click Finish
    (NB. there seems to be a bug here: the Finish button will not always be enabled? I found clicking back to the start of the wizard fixed it)

  • Wait for the install to complete. Accept any signing certificates. Restart the IDE
Install EGit

  • Use Help > Install New Software and click Add

  • Enter a Location of http://download.eclipse.org/egit/updates (see screenshot):
  • Check Eclipse Git Team Provider. Click Next

  • Click Finish

  • Wait for the install to complete. Accept any signing certificates. Restart the IDE
Clone the Seam Forge Repository

  • Use File > Import and choose Projects from Git (see screenshot):
  • Click Clone... and enter a URI of git://github.com/seam/forge.git (see screenshot):
  • Click Next, choose the Master branch, click Next (see screenshot):
  • Click Finish. Wait for the Git repository to clone (may take a while). See screenshot:
  • Click Cancel (not Next!)
Install Maven

  • Use Help > Install New Software

  • Choose to Work with the 'Maven Integration for Eclipse Update Site'

  • Check the 'Maven Integration for Eclipse' box (see screenshot):
  • Click Next, Next, accept the license terms and Finish

  • Wait for the install to complete. Accept any signing certificates. Close the IDE (don't restart it)

  • Edit eclipse/eclipse.ini and add the lines in bold:
    --launcher.XXMaxPermSize
    256m
    -vm
    <path to your JDK>\bin\javaw.exe

    -vmargs
    -Dosgi.requiredJavaVersion=1.5

    (Maven needs Eclipse running under a JDK, not a JRE)

  • Relaunch the IDE
Import Maven Projects

  • Use File > Import. Choose Maven > Existing Maven Projects (see screenshot):
  • Browse to the location of the Git clone (see screenshot):
  • Click Finish. Wait for import of Maven projects (may take a while)
All Seam Forge sub-projects should now be listed under the Package Explorer. There should be no compile errors under the Problems tab, though there may be warnings (as this is still an alpha release). See screenshot: