|
|
|
Samples SamplesXml Code Config API Docs Download Neolectric |
|
Page StructureDxpPages are written as XML source files and parsed with a SAX parser. The parser read the file and calls methods on the DxpNodeLinker to pass data which the linker uses to create a tree of DxpNodes with the root node being the DxpPage itself. A simple src file might look like this... <?xml version="1.0"?> <dxp:DxpPage xmlns:dxp="dxp.neolectric.com" contentType="text/html"> <dxp:Include target="/dxp/common.dxp" node="header"/> -- a buch of nested tags -- <dxp:Include target="/dxp/common.dxp" node="footer"/> </dxp:DxpPage> When an http request is received by the DxpServlet the servlet pulls a DxpPage from it's cache or compiles it from a src file. The request is wrapped by a DxpRequest object and passed to the root node of the DxpPage which then passes it on to it's children. When a child node gets the request it takes some kind of action which often means readng values from the request and writing content to an output buffer. The buffer is sent back to the client by the DxpServlet when the page is finished. The default execution path assumes that child nodes perform a service for their parents so the request is passed to innermost child nodes first, then their siblings and then back up to the parent.
public static void execChildren(DxpRequest req, OutputStream out, DxpNode caller) throws Exception
{
DxpNode node = caller.child; // first child of the parent node
while(node != null)
{
if(node.child != null && node.canPass())
{
node = node.child; // Loop down to last child on branch.
continue; // Conditional tags may not allow a request to pass
}
else // last child on branch reached
node.exec(req, out);
if(node.sibling != null) // if this child has a sibling
{
node = node.sibling; // move to sibling
continue; // follow branch down to it's last child
}
else // no more siblings left on this level
{
node = node.parent; // move back up to parent
if(node == caller) // if this is oringinal parent
break; // break out of the loop rather than repeating it
node.exec(req, out); // exec current parent using any values stored in req by children
node = node.sibling; // move to sibling of parent - if any
}
}
}
Some tags block automatic request passing to thier children by overriding the DxpNode.canPass() method to return false. Then they can decide whether to pass execution based on particular conditions. Some tags use children to gather runtime parameter values and don't want their exec() method called. The Sample pages shows cases where this is done. Processing resultsWhen a node executes it can write data to an output buffer and/or it can store a result back
in the request under a new parameter name...
Subsequent nodes can get stored values when the request is passed to them and do further processing
or format the output. Many nodes override the default execution path so they can control whether a request
gets passsed to their children. The dxp:If node is a good example.
Active tags begin with a recognized prefix that is associated with a namespace and package name.
Passive tags, including html, are considered plain text and stored in a page buffer. In the example
below, the xmlns attribute tells the node linker that any tag beginning with the prefix dxp:
is an active tag and should be used to create a DxpNode and link it into the tree of nodes.The attribute
value dxp.neolectric.com is reversed to form a classpath com.neolectric.dxp, the package that contains
the standard dxp classes.
You may have noticed special parameter ${names} in the examples above. These refer to a name/value pairs that are stored in the request. When they occur in tag attributes they are compiled into dynamic attribute classes. When they occur in blocks of passive text or html code their parameter name and position in the text are stored in an implicit BufferNode. A discussion on dynamic parameters begins here. |