Hi,
Please review the following API proposed to solve the following Trinidad issue,
and discuss here if you have any comments:
[TRINIDAD-2397] Provide API to discover location of document that contains tag
definition for a given component
https://issues.apache.org/jira/browse/TRINIDAD-2397
Requirement:
=========
There are custom tags and components that insert other dynamic contents (i.e subtree of components) into the component
tree. The tags for such dynamically added components come from a document fragment that is different from where the
inserting component / tags come from. For example in Oracle's ADF component library, there are "region", "pageTemplates"
and "declarativeComponent" that does such dynamic includes.
There is often a need to know the location of document where the corresponding tag is defined for a given component. A
couple of usecases are:
1. Browser based "page editor" or "Designtime @ Runtime" kind of products where they will need to change the tags in the
document when a component is customized / edited at runtime.
2. Ability to store any runtime customizations for components against the document where its tag belongs. (For example.
when the columns of dynamically added table is reordered)
The inserting tags / components and the inserted components would be used best to determine the location of the fragment
document that they include / or where they came from. We need to provide some hooks where the authors of such tags /
component are able to provide the URL for the documents given the components.
This enhancement asks for providing an API that provides URL for such documents, and also to publish the necessary hooks
that tag / component authors can implement which then the URL providing implementation can use.
New API Proposed:
=============
Proposed API #1:
--------------------
Two new classes in package "org.apache.myfaces.trinidad.change"
/**
* Strategy implemented for <em>tags</em> that insert document fragments,
returning the URL of the
* fragment for any top-level UIComponents inserted by the tag. When
determining the URL of the
* document that defines the tag corresponding to a target component, clients
will call
* <code>getFramentUrlForInsertedComponent</code> for each registered
* <code>InsertedComponentFragmentLocator</code> on each UIComponent starting
from the target
* component and upto the UIViewRoot and each registered
InsertingComponentFragmentLocator on each
* component from the parent of the target component to the UIViewRoot. If a
non-null URL string
* is returned, the walk of the ancestor chain halts and the returned value is
considered the
* URL string for the document for the target component. If the registered
listeners return
* <code>null</code> for every component in the ancestor chain, the containing
URL is assumed to be
* the URL of the enclosing page.
*
* Implementations of InsertedComponentFragmentLocator are registered using the
normal
* Service Provider Interface pattern. A text file named
* "org.apache.myfaces.trinidad.change.InsertedComponentFragmentLocator" is
placed in the
* META-INF/services directory. This file contains the fully qualified class
names of all the
* InsertedComponentFragmentLocator strategy to register.
*
* @see InsertingComponentFragmentLocator
*/
public abstract class InsertedComponentFragmentLocator
{
/**
* Returns the URL string of the fragment that contains tag corresponding to
* <code>componentToTest</code>, or <code>null</code> if this
InsertedComponentFragmentLocator
* could not determine the URL.
* @param context The FacesContext instance for current request
* @param componentToTest The component to determine the fragment URL for.
* <code>componentToTest</code> will be the <code>targetComponent</code>,
* or one of its ancestors. EL context will NOT be setup for
* <code>componentToTest</code> when this method is called.
* @param targetComponent The target component for which we are ultimately
trying to determine the
* fragment URL. It is assumed that this URL will be same as the URL
* obtained for <code>componenToTest</code>
*/
public abstract String getFragmentUrlForInsertedComponent(
FacesContext context,
UIComponent componentToTest,
UIComponent targetComponent);
}
-------------
/**
* Strategy implemented for <em>components</em> that insert document fragments
to return the URL of
* the fragment currently inserted by this component. When determining the URL
of the
* document that defines the tag corresponding to a target component, clients
will call
* <code>getFramentUrlForInsertedComponent</code> for each registered
* <code>InsertedComponentFragmentLocator</code> on each UIComponent starting
from the target
* component and upto the UIViewRoot and each registered
InsertingComponentFragmentLocator on each
* component from the parent of the target component to the UIViewRoot. If a
non-null URL string
* is returned, the walk of the ancestor chain halts and the returned value is
considered the
* URL string for the document for the target component. If the registered
listeners return
* <code>null</code> for every component in the ancestor chain, the containing
URL is assumed to be
* the URL of the enclosing page.
*
* Implementations of InsertingComponentFragmentLocator are registered using
the normal
* Service Provider Interface pattern. A text file named
* "org.apache.myfaces.trinidad.change.InsertingComponentFragmentLocator" is
placed in the
* META-INF/services directory. This file contains the fully qualified class
names of all the
* InsertingComponentFragmentLocator strategy to register.
*
* @see InsertedComponentFragmentLocator
*/
public abstract class InsertingComponentFragmentLocator
{
/**
* Returns the URL string of the fragment inserted by
<code>componentToTest</code>, or
* <code>null</code> if this InsertingComponentFragmentLocator could not
determine the URL.
* @param context The FacesContext instance for current request
* @param componentToTest The component that possibly inserted the
targetComponent. This component
* will be used to determine the fragment URL for targetComponent.
* <code>componentToTest</code> will be an ancestor of the
* <code>targetComponent</code>. EL context will NOT be setup for
* <code>componentToTest</code> when this method is called.
* @param targetComponent The component to determine the fragment URL for
*/
public abstract String getInsertedFragmentUrl(
FacesContext context,
UIComponent componentToTest,
UIComponent targetComponent);
}
=================
Proposed API #2:
--------------------
The following utility method in
"org.apache.myfaces.trinidad.util.ComponentUtils":
/**
* Gets the location (context relative path) of the document that contains
the tag definition
* corresponding to the supplied component. This implementation uses the
* InsertedComponentFragmentLocator and InsertingComponentFragmentLocator
strategies to determine
* the document path for the supplied component.
* All registered InsertedComponentFragmentLocator services are first asked
for location of the
* document for the supplied component first. If the locator could not be
obtained, then this
* implementation will walk up the component tree and for every ancestor
until the view root,
* call all the registered InsertedComponentFragmentLocator and
InsertingComponentFragmentLocator
* services to obtain the location of the document. If in this process any
non-null value is
* obtained for the document location, the ancestor processing is halted and
the value is
* returned.
*
* @param context The FacesContext instance for the current request
* @param component The component for which the document path is to be
determined
* @return Location of the document fragment that contains the tag
corresponding to the supplied
* component. Returns null if the path cannot be determined.
*/
public static String getDocumentLocationForComponent(
FacesContext context,
UIComponent component)
==================
thanks,
Prakash