public class ClayUtil
{
/**
* @return returns the chains catalog for clay commands.
* @throws Exception
*/
static protected Catalog getCatalog() throws Exception
{
// Look up the "shale" catalog, creating one if necessary
Catalog catalog = CatalogFactory.getInstance().getCatalog(
Globals.CLAY_CATALOG_NAME);
if (catalog == null)
{
ConfigParser parser = new ConfigParser();
URL url = ""> Globals.CLAY_RESOURCE_NAME);
if (url == null)
{
throw new IllegalArgumentException(Globals.CLAY_RESOURCE_NAME);
}
parser.parse(url);
catalog =
CatalogFactory.getInstance().getCatalog(
Globals.CLAY_CATALOG_NAME);
}
return catalog;
}
/**
* @param jsfid the template id.
* @return returns the component bean associated with the template.
*/
static protected ComponentBean getRootElement(String jsfid)
{
ConfigBean config = ConfigBeanFactory.findConfig
(jsfid);
if (config == null)
{
throw new NullPointerException("clay config not loaded");
}
// find the top-level display element associated with the subtree
ComponentBean b = config.getElement(jsfid);
if (b == null)
{
throw new NullPointerException("clay template with following jsfid not found: " + jsfid);
}
return b;
}
/**
* @param parent the parent component.
* @param jsfid the template jsfid.
* @param symbols the symbols collection used by the template.
*/
static public UIComponent loadTemplate(UIComponent parent, String jsfid, Map symbols)
{
ComponentBean cb = getRootElement(jsfid);
ClayContext clayContext = new ClayContext();
clayContext.setChild(null);
clayContext.setDisplayElement(cb);
clayContext.setJsfid(jsfid);
clayContext.setFacesContext(FacesContext.getCurrentInstance());
clayContext.setSymbols(symbols);
clayContext.setRootElement(cb);
clayContext.setParent(parent);
clayContext.setChildIndex(parent.getChildCount());
Catalog catalog = null;
try
{
catalog = getCatalog();
} catch (Exception e)
{
throw new RuntimeException(e);
}
Command command = catalog.getCommand(Globals.ADD_COMPONENT_COMMAND_NAME);
try
{
command.execute(clayContext);
} catch (Exception e)
{
throw new RuntimeException(e);
}
return (UIComponent)clayContext.getChild();
}
}
/**
* @param symbols the symbols collection.
*/
abstract protected void setSymbols(Map symbols);
protected UIComponent createComponentInstance(FacesContext context, String templateId)
UIComponent parentComponent = getParentComponent();
if(parentComponent == null)
{
throw new JspException("parent componnet is null");
}
//initialize symbols
TreeMap symbols = new TreeMap();
setSymbols(symbols);
//load template
return ClayUtil.loadTemplate(parentComponent, getTemplateId(), symbols);
}
<attributes>
<set name="id" value="@fieldColumn"/>
</attributes>
<element renderId="1" jsfid="outputText" facetName="header">
<attributes>
<set name="id" value="@fieldHeaderText"/>
<set name="value" value="@headerText"/>
</attributes>
</element>
<element renderId="2" jsfid="outputText">
<attributes>
<set name="id" value="@field"/>
<set name="value" value=" [EMAIL PROTECTED]"/>
</attributes>
</element>
</component>
<component jsfid="mmisSortableColumn" extends="mmisColumn">
<element renderId="1" jsfid="myfacesCommandSortHeader" facetName="header">
<attributes>
<set name="id" value="@fieldHeader"/>
<set name="columnName" value="@field"/>
</attributes>
<element renderId="1" jsfid="outputText">
<attributes>
<set name="id" value="@fieldHeaderText"/>
<set name="value" value="@headerText"/>
</attributes>
</element>
</element>
</component>
<templates:column field="abc"/>
<templates:column field="def" sortable="true"/>
<templates:column field="ghi"/>
<templates:column field="jkl"/>
</templates:datatable>
>I agree that facelets can be used. But I have created simple
>util methods that use clay api to load a component or a sub tree.
>I cannot plug this into Myfaces implementation as createComponentInstance
>is private. It can be plugged into sun implementation.
>
>Clay as it is adds a clay component to the tree and while rendering this component
>loads the subtree. Hence one cannot use clay as it is for templating. For example:
>
>The project I am working mostly has panels displaying atleast one list. We use datatable.
>All of the datatable attributes are common except for the bean name. Instead of every
>jsp containing the list, specify all these attributes I created a template using clay for
>datatable with all the attributes set in some cases using symbols.The intention is to
>create a custom tag whose createComponentInstance will create the component from this>template. Simila rly th e column can be also be templated.
>
>Following are some issues with using clay as it is . Some of them apply to facelets also.
>
>Clay grafts a sub tree into an existing tree. But this is done by adding the clay to main
>tree and the clay component adds the sub tree as its child.
>
>For example:
>
>When using clay to load a template, the clay tag is used in jsp.
>
><clay:clay id="abc" jsfid="templatename">
>
></clay:clay>
>
>The execution of this tag adds clay component to the view tree and while rendering, the clay
>component builds the sub tree from the template and adds it as a child.
>
>The tree is as follows:
>
>Viewroot
>|__clay
>| |__template contents
>|
>|__other page component..
>
>It cannot be used to load a template for a container.
>For example:
>> ;  ; When using datatable normally the code looks as follows:
>
><t:datatable attributes…>
> <h:column>
> Column contents
> </h:column>
> <h:column>
> Column contents
> </h:column>
></t:datatable>
>
>The tree is as follows:
>
>Datatable
>
>|__column
>| |__column contents
>|
>|__column
>
> |__column contents
>
> As there are many attributes that need to be definedon the datatable, we want to create a
>template. So with clay it will be as follows:
>
><clay:clay id="mydatalist" jsfid="mytable">
> <h:column>
> Column contents
> </h:column>
> <h:column>
> Column conte nts
> </h:column>
></clay:clay>
>The clay JSP tag should not be used this way. The only valid nested element
under the clay tag should be the <clay:symbol/> tag. There is not a tag library
validator to enforce this yet.The basic strategy that clay uses is to create a meta data layer that gives more
reuse options. So, the subtree that clay creates is always from a meta data source
other than nested JSP tags (symbol tag being the exception).
The shale-clay-usecases shows several examples but it's not available as a nightly build yet.
We have just switched over to maven 2 builds which means it's about as easy as it gets
to build from the repository.
Clay gives you several options to build this meta data
( http://struts.apache.org/struts-shale/features-reusable-views.html#Clay_View_Composition_Options).There is actually now another option that we are working out the kinks on. You can
define an xhtml template using multiple namespaces similar to facelets. The shale-clay-usecases app
shows an example of this
(http://svn.apache.org/viewvc/struts/shale/trunk/shale-apps/shale-clay-usecases/src/main/webapp/rolodex/jrolodex.html?view=markup )..>But what happens is the tree will be as follows:
>
>Clay
>|__datatable
>|
>|__column
>| |__column contents
>|
>|__column
> |__column contents
>
>
>The template contents become children of clay as well as the components inside
>clay tag body also become its children.
>> [snippet]
Gary

