Saturday, April 30, 2011

Object User Interface Mapper (OIM): Metawidget v1.15

Version 1.15 of Metawidget, the Object User Interface Mapping tool (OIM) is now available! This release includes the following enhancements:
As always, the best place to start is the Reference Documentation:

http://metawidget.org/doc/reference/en/pdf/metawidget.pdf

Special thanks to Renato Garcia and Lincoln Baxter III for their help with this release!

Your continued feedback is invaluable to us. Please download it and let us know what you think.

Thursday, April 28, 2011

Metawidget: RichFaces 4 support

The next release of Metawidget (v1.15) will include support for RichFaces 4 (previously we only supported 3.3.3.Final). Code and unit tests are already available in SVN, and here are some screenshots:

This support requires MyFaces 2.0.5 or above, or a version of Mojarra that includes this fix.

Wednesday, April 20, 2011

Metawidget: Streamlined Configuration

The next release of Metawidget (v1.15) will include a small enhancement to the metawidget.xml syntax used by ConfigReader. ConfigReader has always been designed to automatically recognise and reuse immutable instances. This works both when configuring multiple Metawidgets, and configuring multiple settings for a single Metawidget. So if you did...

<inspectors>
   <array>
      <java5Inspector xmlns="java:org.metawidget.inspector.java5" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig">
         <propertyStyle>
            <javaBeanPropertyStyle xmlns="java:org.metawidget.inspector.impl.propertystyle.javabean" config="JavaBeanPropertyStyleConfig">
               <supportPublicFields>
                  <boolean>false</boolean>
               </supportPublicFields>
               <privateFieldConvention>
                  <format>'m'{1}</format>
               </privateFieldConvention>
            </javaBeanPropertyStyle>

         </propertyStyle>                  
      </java5Inspector>
      <metawidgetAnnotationInspector xmlns="java:org.metawidget.inspector.annotation" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig">
         <propertyStyle>
            <javaBeanPropertyStyle xmlns="java:org.metawidget.inspector.impl.propertystyle.javabean" config="JavaBeanPropertyStyleConfig">
               <supportPublicFields>
                  <boolean>false</boolean>
               </supportPublicFields>
               <privateFieldConvention>
                  <format>'m'{1}</format>
               </privateFieldConvention>
            </javaBeanPropertyStyle>

         </propertyStyle>                  
      </metawidgetAnnotationInspector>
   </array>
</inspectors>

...ConfigReader would be smart enough to reuse the same javaBeanPropertyStyle instance. But you still had to specify all javaBeanPropertyStyle's configuration options twice. In v1.15 you can instead use id and refId to refer from one setting to another:

<inspectors>
   <array>
      <java5Inspector xmlns="java:org.metawidget.inspector.java5" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig">
         <propertyStyle>
            <javaBeanPropertyStyle xmlns="java:org.metawidget.inspector.impl.propertystyle.javabean" config="JavaBeanPropertyStyleConfig" id="myPropertyStyle">
               <supportPublicFields>
                  <boolean>false</boolean>
               </supportPublicFields>
               <privateFieldConvention>
                  <format>'m'{1}</format>
               </privateFieldConvention>
            </javaBeanPropertyStyle>
         </propertyStyle>                  
      </java5Inspector>
      <metawidgetAnnotationInspector xmlns="java:org.metawidget.inspector.annotation" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig">
         <propertyStyle>
            <javaBeanPropertyStyle refId="myPropertyStyle" />
         </propertyStyle>                  
      </metawidgetAnnotationInspector>
   </array>
</inspectors>

It's a small thing, but can shorten your metawidget.xml in a big way.

Feedback welcome!

Monday, April 11, 2011

Metawidget: Maven Snapshot Releases

I'm thrilled to say that the first snapshot releases of Metawidget 1.15 are now available in the JBoss Snapshot Repository at https://repository.jboss.org/nexus/content/repositories/snapshots/org/metawidget:

<repository>
   <id>jboss-snapshots</id>
   <url>https://repository.jboss.org/nexus/content/repositories/snapshots</url>
</repository>
...
<dependency>
   <groupId>org.metawidget.modules</groupId>
   <artifactId>metawidget-all</artifactId>
   <version>1.15-SNAPSHOT</version>
</dependency>

I plan to be staging the modules here for a few weeks before the final 1.15 release. I'd be most grateful to anybody who could download them and take the new fine-grained module system for a spin.

My thanks to Renato Garcia for his help with the Maven migration.

Feedback most welcome!

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!