Hi Mike,
Rather than answer your questions as you asked them, I'll try to
explain a high-level overview and then drill down on the points you
need to know. I think in the process, your questions will get
answered. Feel free to call me or email me if I don't provide enough
information in this email.
The concept of the "DynamicTreeNodeFactory" is it will generate a node
*and* 0 or more nodes under that node. It will do this from *any* data
source as long as their is an "adaptor" to that data source.
So in your case, you have children of a tree node that you want to
display based on data returned for your api's (or however you get the
data... that's not important for this overview). So first off, the
parent of the dynamic children is going to be the "dynamicTreeNode" --
I think you already know that, but I want to make sure. The children
exist in some data structure which you obtain via some backend calls
(not important). The DynamicTreeNode factory will require an "adaptor"
to know how to interpret your data and generate TreeNode objects for
them. So, your work will be to create this adaptor class that
understands your data structure.
So conceptually:
* Page contains dynamicTreeNode
* dynamicTreeNode uses a specific "adaptor" that can walk your data
structure
* DynamicTreeNodeFactory will use your adaptor to walk your data
structure and create the children.
Before we look at the adaptor class, lets look at the .jsf file.
Here's an example from peTree.jsf:
<dynamicTreeNode id="enterpriseApplications"
treeAdaptorClass="com.sun.enterprise.tools.admingui.tree.MBeanTreeAdaptor"
objectName="com.sun.appserv:type=applications,category=config"
methodName="getAllDeployedJ2EEApplications"
text="$resource{i18n.tree.enterpriseApps}"
url="/applications/enterpriseApplications.jsf"
target="main"
attributeName="name"
childImageURL="resource/images/application.gif"
childTarget="main"
childExpanded="$boolean{false}"
childURL="applications/enterpriseApplicationsEdit.jsf?appName=#{$this{valueBinding}.text}">
<!facet image>
<sun:iconHyperlink id="abc" icon="TREE_FOLDER"
url="/applications/enterpriseApplications.jsf" target="main"
border="$int{0}" immediate="$boolean{true}" />
</facet>
<!filterTree filterSystemApps() />
</dynamicTreeNode>
First notice that the dynamicTreeNode uses the "treeAdaptorClass"
attribute to specify the adaptor instance. Your instance belongs here.
Next notice "objectName", "methodName", and "attributeName"... these
are *NOT* used by the dynamicTreeNode factory. If you look in
MBeanTreeAdaptor... you'll find they are used *there*. These
properties are specific to the MBeanTreeAdaptor (see the init()
method). You will most likely want to have your own properties, you
can use whatever you'd like... but you're responsible for retrieving
them in your Adaptor class.
Next, look at "text", "url", "target". These are properties for the
parent node (remember, this factory will create a node + dynamic
children... these properties define the "node"). However, these too
are interpreted by the MBeanTreeAdaptor class. This means you'll need
to do something similar or identical in your code (see
MBeanTreeAdaptor.getFactoryOptions). The reason this is done this was
is to give full control to the Adaptor class, even for the parent node.
Next look at the facet "image". JSFTemplating will automatically set
this on the component (the parent of the dynamic children), so nothing
is done in the Adaptor class for this (although it can be added via the
Adaptor code if you prefer this vs. the .jsf file).
Next look at the "child*" properties. The MBeanTreeAdaptor class uses
these properties when specifying properties for the dynamic children.
Last, look at the "filterTree" event... I'm not going to explain this
unless you need it. It allows you to filter the children, here we're
getting rid of system applications that shouldn't be shown to the user.
Ok, so that shows where the information comes from. Now lets look at
how its processed and what you need to do. First lets look at the
factory. You don't need to do anything in DynamicTreeNodeFactory.
There is some useful documentation at the top of this file, though (or
at least I hope its useful). Key operations this factory invokes:
1) Instantiates your TreeAdaptor implementation
2) Calls yourTreeAdaptor.init() -- your opportunity to do setup tasks
(i.e. get your data)
3) Calls yourTreeAdaptor.getTreeNodeObject() -- your implementation can
return *anything* that is useful to you
4) Walks your data structure by calling:
* yourTreeAdaptor.getId(obj)
* yourTreeAdaptor.getFactoryClass(obj)
* yourTreeAdaptor.getFactoryOptions(obj)
- Creates UIComponent based on information from above calls
* yourTreeAdaptor.getFacets(comp, obj)
* yourTreeAdaptor.getHandlersByType(comp, obj)
* yourTreeAdaptor.getChildTreeNodeObjects(obj)
- Loop throw all childTreeNodeObjects recursing back to the
beginning of Step 4.
So as you can see, the TreeAdaptor does all the "work" while the
factory walks through the algorithm and extracts the required
information and does the actual instantiation and other mundane JSF
required tasks. You can also see that in step 3, *your TreeAdaptor
implemenation* returns some object. This object means *nothing* to the
DynamicTreeNodeFactory, but is used in *every* method call to your
TreeAdaptor implementation. This "obj" is anything that helps you
retrieve data from your data structure. This could include objects in
your data structure itself, or identifiers to objects in your data
structure. It looks like MBeanTreeAdaptor uses the "objectName" as the
value returned from step #3.
Notice the last * under step #4, it returns a List<Object> which
are *new* "obj" values that will be passed into each method called in
step #4. So it is important that your TreeAdaptor use the "obj" value
to do something useful with it. It is your only way to identify where
you are in your own data structure.
Finally... lets look at the Adaptor class you will need to write.
Looking at the methods above, you'll need to implement all of these...
although the TreeAdaptorBase provides an implementation for some of
this. You are not likely to need "getHandlersByType" -- so don't worry
about it unless you think you need it. The rest you'll probably need.
Take a look at the JavaDoc for:
com.sun.jsftemplating.component.factory.tree.TreeAdaptor;
This JavaDoc should explain what each method does. Please let me know
if you need clarification for any of these methods... I'll fix the
JavaDoc. Also, look at TreeAdaptorBase in the same package to see what
it provides for you (very small class... easy read).
I hope this provides you with all the information you need to create an
Adaptor that is capable of walking your data structure... let me know
if you need more!
Thanks!
Ken Paulsen
ken.paulsen@sun.com
Mike Wright wrote:
Hi Ken,
I'm trying to get JBI leaf nodes working. I implemented a
JBITreeAdaptor that gets control with a "method" parameter for one of
three kinds of children. However the getChildTreeNodeObjects method is
always called with a null nodeObject argument. If I ignore that and
always return a list of children, I get a stack overflow. I have
several questions:
1. the existing examples I could find use an MBean tree adaptor and
a web services tree adaptor, but both depend on AMXUtils and MBeans
with ObjectNames, methodNames, attributeNames, etc. JBI doesn't have
anything like this. I was hoping to just have the tree adaptor return
a list of child node names. 1a. how do I get the nodeObject passed in?
which treeNode attribute(s) do I need to worry about? methodName is
getting passed okay. I tried to remove objectName or set it to "na"
but that didn't seem to affect anything (since I don't have any
AMXUtil/ObjectName related code in my JBITreeAdaptor)
1b. what is the type of element in the List (built from an Object[])?
Will Strings work? (the problem here is that, due to the null
argument, I never return this List, so I cannot yet tell if Strings
will work, or do I need to create some wrapper object, and if so, what
type?)
2. can you give me an overview of the essential flows I need to
worry about? i.e. which methods get called in what order, for the
dynamic tree nodes?
Regards,
Mike
-/-