org.apache.myfaces.orchestra.dynaForm.jsf.component
Class DynaForm

java.lang.Object
  extended by javax.faces.component.UIComponent
      extended by javax.faces.component.UIComponentBase
          extended by org.apache.myfaces.orchestra.dynaForm.jsf.component.DynaForm
All Implemented Interfaces:
javax.faces.component.StateHolder

public class DynaForm
extends javax.faces.component.UIComponentBase

A DynaForm component dynamically creates child jsf component objects to render all the persistent fields of an arbitrary java object.

This component can be nested within a UIData. In this case the data model of the UIData is assumed to be a list of persistent objects, each of which is of the type specified by the "uri" attribute of this component. A UIColumn component is generated for each persistent property of the class specified by "uri".

This component can also be used as a child of something other than a UIData, in which case it simply outputs a (label, field) pair of components for each persistent property of the class specified by the "uri" parameter. It is up to the parent component to lay out these component pairs appropriately.

The standard "value" property must be an EL expression that returns the object whose properties are to be displayed or edited. When used within a UIData, this will normally return the "var" property of the datatable.

For documentation on the configurable properties of this component, see:

Note that this class has no Renderer; this class dynamically modifies the component tree to add components, but has no actual representation itself and therefore needs no renderer. See method initView.


Nested Class Summary
protected static class DynaForm.AddComponentSimple
          Simply attach a (label, value) pair of JSF components that represent a single persistent property.
protected static class DynaForm.AddComponentToTable
          Create a UIColumn component to wrap a (label, value) pair of JSF components that represent a single persistent property.
 
Field Summary
static String COMPONENT_FAMILY
           
static String COMPONENT_TYPE
           
static String DEFAULT_RENDERER_TYPE
           
static String DYNA_FORM_CREATED
           
static String DYNA_FORM_URI
           
 
Constructor Summary
DynaForm()
           
 
Method Summary
protected  void addComponents(javax.faces.context.FacesContext context, DynaForm dynaForm, javax.faces.component.UIComponent layoutComponent, ViewType viewType)
          create and add the components to the layout component.
protected  JsfGuiBuilder createGuiBuilder(javax.faces.context.FacesContext facesContext)
           
protected  DynaForm findParentDynaForm(DynaForm start)
          try to find a parent dyna form+
 String getBundle()
           
protected  UriResolver.Configuration getConfiguration()
          Get the overall configuration based on the current value of the uri property.
static DynaForm getDynaForm(javax.faces.component.UIComponent component)
          Find the dynaForm component
 javax.el.ELContext getELContext()
          Note that this method should only be called when _FacesUtils.useValueExpression is true.
 Extractor getExtractor()
           
 String getFamily()
           
 DynaConfigs getFormConfigs()
          get access to the special form configurations
 NewComponentListener getNewComponentListener()
           
 String getUri()
           
 String getValueBindingPrefix()
           
protected  String getValueBindingPrefix(DynaForm dynaForm, javax.faces.component.UIComponent layoutComponent)
           
protected  ViewType getViewType(javax.faces.component.UIComponent startComponent)
          determine the current view type "list" means: the layout component "is a" or "is embedded in an" list component (UIData) "form" means: anything else
 void initView(javax.faces.context.FacesContext context)
          Dynamically compute and add child components to the current tree.
 boolean isDisplayOnly()
           
 boolean isExclusiveFields()
           
 boolean isIdAsDisplayOnly()
           
 boolean isRendered()
           
protected  boolean processPreviouslyAdded(javax.faces.context.FacesContext context, javax.faces.component.UIComponent root)
          check if we already added components to the layout component.

if this is the case then: keep them cached and avoid readd in development mode: remove the components in production mode: keep them cached

TODO: need to figure out whats the best way to recreate the components

 void removeDynaFormCreatedComponents(javax.faces.component.UIComponent base)
           
 void restoreState(javax.faces.context.FacesContext context, Object stateArray)
           
 Object saveState(javax.faces.context.FacesContext context)
           
 void setBundle(String bundle)
          The bundle to use to convert property names to localised label strings.
 void setDisplayOnly(boolean displayOnly)
          Display the whole form in read only mode, ie all the JSF components generated to display persistent properties are "read only".
 void setELContext(javax.el.ELContext elcontext)
           
 void setExclusiveFields(boolean exclusiveFields)
          Process only fields listed by their facets
 void setIdAsDisplayOnly(boolean idAsDisplayOnly)
          Display id fields (ie the key fields of the persistent object) in the form in read only mode.
 void setNewComponentListener(NewComponentListener newComponentListener)
          Normally DynaForm will try to figure out how to add components to the JSF tree.
 void setUri(String uri)
          Specifies how to obtain the metadata for the value object.
 void setValueBindingPrefix(String valueBindingPrefix)
          Specify how to get and set the model value for each persistent property of the value object.
 
Methods inherited from class javax.faces.component.UIComponentBase
addFacesListener, broadcast, decode, encodeBegin, encodeChildren, encodeEnd, findComponent, getAttributes, getChildCount, getChildren, getClientId, getFacesContext, getFacesListeners, getFacet, getFacets, getFacetsAndChildren, getId, getParent, getRenderer, getRendererType, getRendersChildren, getValueBinding, isTransient, processDecodes, processRestoreState, processSaveState, processUpdates, processValidators, queueEvent, removeFacesListener, restoreAttachedState, saveAttachedState, setId, setParent, setRendered, setRendererType, setTransient, setValueBinding
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

COMPONENT_TYPE

public static final String COMPONENT_TYPE
See Also:
Constant Field Values

DEFAULT_RENDERER_TYPE

public static final String DEFAULT_RENDERER_TYPE
See Also:
Constant Field Values

COMPONENT_FAMILY

public static final String COMPONENT_FAMILY
See Also:
Constant Field Values

DYNA_FORM_CREATED

public static final String DYNA_FORM_CREATED
See Also:
Constant Field Values

DYNA_FORM_URI

public static final String DYNA_FORM_URI
See Also:
Constant Field Values
Constructor Detail

DynaForm

public DynaForm()
Method Detail

getFamily

public String getFamily()
Specified by:
getFamily in class javax.faces.component.UIComponent

getNewComponentListener

public NewComponentListener getNewComponentListener()
See Also:
setNewComponentListener(org.apache.myfaces.orchestra.dynaForm.jsf.guiBuilder.impl.jsf.NewComponentListener)

setNewComponentListener

public void setNewComponentListener(NewComponentListener newComponentListener)
Normally DynaForm will try to figure out how to add components to the JSF tree. In case you would like to customize that, you cann provide your own NewComponentListener.


getUri

public String getUri()
See Also:
setUri(java.lang.String)

setUri

public void setUri(String uri)
Specifies how to obtain the metadata for the value object.

This is a string of form "inspector:classname". The inspector part ndicates which of the configured Extractor implementations should be used to obtain the metadata for this class. The classname is of course the concrete class of the specified object.

For example, "ejb:fqn.to.model.Entity" means use the EJB3-based extractor implementation to obtain metadata about the given entity

TODO: why can't value.getClass() be used for the classname part of the uri? Maybe because the value EL expression can map to a null property when creating a new instance?

See Also:
UriResolver

getValueBindingPrefix

public String getValueBindingPrefix()
See Also:
setValueBindingPrefix(java.lang.String)

setValueBindingPrefix

public void setValueBindingPrefix(String valueBindingPrefix)
Specify how to get and set the model value for each persistent property of the value object.

When the JSF components that correspond to the individual persistent properties of the value object are created, they need EL expressions to tell them how to access the corresponding model value.

The EL expression used for each created component is of form #{valueBindingPrefix.propname}.

Of course valueBindingPrefix will normally refer to the same object that the "value" property refers to. In fact, there probably isn't any other sane value for this property.

TODO: Can we get rid of this attribute? Either call getValueBinding().getExpressionString() or create a special ValueBinding subclass that takes a "base object" parameter which we can point at the result of evaluating the main value expression.


getBundle

public String getBundle()
See Also:
setBundle(java.lang.String)

setBundle

public void setBundle(String bundle)
The bundle to use to convert property names to localised label strings.

For each persistent property on the value object, a pair of components (label and value) are created. The label text is computed by using the persistent property name as a key into the specified bundle.

This must be the name of a managed bean that implements Map.


setDisplayOnly

public void setDisplayOnly(boolean displayOnly)
Display the whole form in read only mode, ie all the JSF components generated to display persistent properties are "read only".


isDisplayOnly

public boolean isDisplayOnly()
See Also:
setDisplayOnly(boolean)

setIdAsDisplayOnly

public void setIdAsDisplayOnly(boolean idAsDisplayOnly)
Display id fields (ie the key fields of the persistent object) in the form in read only mode.

Defaults to false.

When editing existing objects this should be set to true, as it is not possible to modify the key of an existing entity. When creating a new instance this should be set to true if the key is an auto-generated surrogate key, but false if the key to this entity is a "business key".


isIdAsDisplayOnly

public boolean isIdAsDisplayOnly()
See Also:
setIdAsDisplayOnly(boolean)

setExclusiveFields

public void setExclusiveFields(boolean exclusiveFields)
Process only fields listed by their facets

TODO: document this properly. What does this do exactly??


isExclusiveFields

public boolean isExclusiveFields()
See Also:
setExclusiveFields(boolean)

restoreState

public void restoreState(javax.faces.context.FacesContext context,
                         Object stateArray)
Specified by:
restoreState in interface javax.faces.component.StateHolder
Overrides:
restoreState in class javax.faces.component.UIComponentBase

saveState

public Object saveState(javax.faces.context.FacesContext context)
Specified by:
saveState in interface javax.faces.component.StateHolder
Overrides:
saveState in class javax.faces.component.UIComponentBase

getConfiguration

protected UriResolver.Configuration getConfiguration()
Get the overall configuration based on the current value of the uri property.

This returns an object that simply pairs an Extractor object with the remaining part of the URI. The Extractor instance selected is specified by the "protocol" part of the URI.

See Also:
UriResolver

getExtractor

public Extractor getExtractor()

findParentDynaForm

protected DynaForm findParentDynaForm(DynaForm start)
try to find a parent dyna form+


getDynaForm

public static DynaForm getDynaForm(javax.faces.component.UIComponent component)
Find the dynaForm component


getFormConfigs

public DynaConfigs getFormConfigs()
get access to the special form configurations


getELContext

public javax.el.ELContext getELContext()
Note that this method should only be called when _FacesUtils.useValueExpression is true.

This is needed when using either JSF1.2 or (JSF1.1 + facelets).

It is still not clear why we need this anyway; instead of storing a context for later use, why not just use the context available at the time an expression must be evaluated?


setELContext

public void setELContext(javax.el.ELContext elcontext)

isRendered

public boolean isRendered()
Overrides:
isRendered in class javax.faces.component.UIComponentBase

initView

public void initView(javax.faces.context.FacesContext context)
Dynamically compute and add child components to the current tree.

This method is required to be invoked from the TagHandler when an instance of this component is created. Components are created based upon the class specified by the "uri" property, and added as children of the parent component of this component.

This component itself never has any components, and never generates any output into the response stream.

It would be much nicer if this component could be the parent of the components it dynamically creates, but that doesn't work well with an h:panelGrid or h:dataTable component as the parent; a panelGrid counts its children while a dataTable counts its UIColumn children. To make things work, the created components must therefore be direct children of the parent. Note that this component is also a child of the parent, but because it marks itself as rendered=false it does not affect the behaviour of parent components that count their (rendered) children.

Note also that although this method is capable of deleting previously-created components and creating a new set, at the moment this method is only invoked by the taghandler when this component is created. That means that the "uri" parameter is only used on first access to the view, and is ignored thereafter.


removeDynaFormCreatedComponents

public void removeDynaFormCreatedComponents(javax.faces.component.UIComponent base)

getViewType

protected ViewType getViewType(javax.faces.component.UIComponent startComponent)
determine the current view type


addComponents

protected void addComponents(javax.faces.context.FacesContext context,
                             DynaForm dynaForm,
                             javax.faces.component.UIComponent layoutComponent,
                             ViewType viewType)
create and add the components to the layout component. TODO: clean this method up. It still had artefacts from when this code was in a separate Renderer class.


getValueBindingPrefix

protected String getValueBindingPrefix(DynaForm dynaForm,
                                       javax.faces.component.UIComponent layoutComponent)

createGuiBuilder

protected JsfGuiBuilder createGuiBuilder(javax.faces.context.FacesContext facesContext)

processPreviouslyAdded

protected boolean processPreviouslyAdded(javax.faces.context.FacesContext context,
                                         javax.faces.component.UIComponent root)
check if we already added components to the layout component.

if this is the case then:

TODO: need to figure out whats the best way to recreate the components

Returns:
true if we have to add our components again


Copyright © 2012 The Apache Software Foundation. All Rights Reserved.