With Seam you have options for component configuration. One of those options is configuration through use of components.xml. This is especially valuable when you have components that are reused among application instances as it allows the configuration to be specific based on the needs of the application. Seam provides a very simple approach to limit or even eliminate configuration errors through the use of Namespaces and schemas.

It is quite ugly and error-prone to configure components in the following manner:

@Name("myComponent")
public class MyComponent {
  private Map<String, String> componentMapping;
  private BigDecimal someDecimalValue;
  ... ...
  // component getters and setters
}

In components.xml:

... ...
<component name="myComponent">
  <property name="someDecimalValue" value="22.2" />
  <property name="componentMapping">
    <key>someKey</key> <value>someValue</value>
    ... ...
  </property>
  ... ...
</component>
... ...

Generating a Namespace and schema for your Seam components is actually quite simple and by taking the time to do this, you gain the benefits of:

  • auto-completion within the IDE (or your favorite XML editor)
  • validation of your configuration prior to deployment (attributes and even values if restrictions are defined)
  • very lean configuration (makes your custom components look good 😉 )

The Seam Reference Guide simply references the schemas shipped with Seam as examples for generating your own, but I thought a brief tutorial for those less familiar with XML schemas might be helpful.

Creating a Namespace

First off, you need to create a Namespace. As the documentation demonstrates, this is actually quite simple with Seam through the use of the @Namespace annotation. Just create a file named package-info.java in the package of your components:

@Namespace(value="http://solutionsfit.com/example/custom")

package com.solutionsfit.example.custom;

import org.jboss.seam.annotations.Namespace;

All of the components for this Namespace must be in this package. You cannot have the same Namespace referenced in multiple package-info.java files. While this makes sense it can be a hinderance in situations where you have sub-packaging.

Now we can reference the Namespace in our components.xml:

<components xmlns="http://jboss.com/products/seam/components"
            xmlns:custom="http://solutionsfit.com/example/custom"
            ... ...
            <custom:my-component ... />

As you will note, component names and attribute names are specified in the hyphenated form when using Namespaces. I refer you to the Seam Reference Guide for more details on configuring Namespaced elements.

Manually generating the schema

Now for the schema. So we have a Namespace defined for our custom components, but it would be great to have auto-complete and validation in our components.xml. The following template should help you get there:

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    targetNamespace="http://solutionsfit.com/example/custom"
    xmlns:custom="http://solutionsfit.com/example/custom"
    xmlns:components="http://jboss.com/products/seam/components"
    attributeFormDefault="unqualified">

  <xs:import namespace="http://jboss.com/products/seam/components"
    schemaLocation="http://jboss.com/products/seam/components-2.0.xsd"/>

  <xs:element name="my-component">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="component-mapping" minOccurs="1" maxOccurs="1"
          type="components:mapProperty" />
      </xs:sequence>
      <xs:attributeGroup
          ref="components:attlist.component"/>
      <xs:attributeGroup
          ref="custom:attlist.my-component" />
    </xs:complexType>
    ... ...
    <xs:attributeGroup id="attlist.my-component">
      <xs:attribute name="some-decimal-value"
        type="xs:decimal" required="false">
      ... ...
    </xs:attributeGroup>
  </xs:element>
  ... ...

You’ll notice that we import the Seam components-2.0.xsd and reference it as a namespace. This gives us access to the basic component attributes that will be configurable on your component.

Also notice, on my-component we reference an attribute group components:attlist.component. This attribute group is defined in the components Namespace we imported and provides the attributes you’d expect for a Seam component (i.e. name, scope, auto-create, …). In addition, we define an element named component-mapping of type components:mapProperty. Here we have used a type defined in the components Namespace. This is very convenient as we can now specify the following our components.xml:

... ...
<custom:my-component some-decimal-value="22.2">
  <custom:component-mapping>
    <key>someKey</key> <value>someValue</value>
    ... ...
  </custom:component-mapping>
... ...

Another type multiValuedProperty can be used for Lists configured within your component.

You may also note that I specified restrictions within my component-mapping element. minOccurs=1 and maxOccurs=1 will ensure that the component-mapping element is provided if my-component is specified in the components.xml definition. It is good practice to provide these types of restrictions to avoid configuration errors at run-time which can be difficult to debug. By specifying them in our schema, our XML editor will notify us of validation issues. A good tutorial on schema definitions can be found at w3schools.

Referencing the schema

Once my schema is specified, I can simply reference the schema in components.xml in the xsi:schemaLocation attribute:

<components xmlns="http://jboss.com/products/seam/components"
  xmlns:core="http://jboss.com/products/seam/core"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation=
    "http://jboss.com/products/seam/core
     http://jboss.com/products/seam/core-2.0.xsd
     http://jboss.com/products/seam/components
     http://jboss.com/products/seam/components-2.0.xsd
     http://solutionsfit.com/example/component
     http://solutionsfit.com/example/component-1.0.xsd">
  ... ...

But, there is one final step to get auto-complete and validation. If you attempt to validate the XML at this point you will notice errors on your custom component configuration. This is simply because Eclipse cannot find the XSD we specified.

Craig Walls posted a blog entry back in August on how to fix errors in Eclipse with Spring Modules in your XML. The same fix applies for your own custom XSDs. Simply reference the XSD on your local drive from the “Add XML Catalog Entry” dialog as Craig describes. Once you’ve referenced your schema, refresh your components.xml and you are in business! You will now have auto-complete and validation for your custom components.

Sidenote: Auto-generation of schemas for custom components would be a great feature addition for seam-gen. While it would not be trivial to implement, if interest in this posting is high enough I would be happy to contribute a patch as soon as my schedule permits 😉 .