|
|
|
Samples SamplesXml Code Config API Docs Download Neolectric |
|
Creating new tagsdxp tags are a web interface to run values in and out of your application classes. The intent is to promote reuseable code that can be connected like building blocks to create many different web applications. It is not designed to build complex, one of a kind, applications through page scripting. Creating your own tagsCustom tags can extend the basic DxpNode or one of it's subclasses. In most cases you will use your own package and refer to it by adding an xmlns attribute in pages it runs on. Here is a bare bones example.
// file: MyNode.java
package com.mydomain.xyz;
// minimum classes required by dxp
import com.neolectric.dxp.DxpNode;
import com.neolectric.dxp.DxpRequest;
import com.neolectric.dxp.DxpException;
// import any other neolectric classes you need by
// name but don't import com.neolectric.pkgname.*;
// imports from other sources
import java.io.*;
import org.xml.sax.Attributes;
public class MyNode extends DxpNode {
/** Called by the node linker to construct a DxpNode before intializing it.*/
public MyNode(){};
/** Supply an init() method to create Objects from attributes. */
public void init(String id, Attributes atts) throws Exception
{
// this is where you set attributes and ready your class to do work
}
/** Most tags override DxpNode.exec() to perform some useful work.*/
public void exec(DxpRequest req, OutputStream out) throws Exception
{
// this is where you do work when the request is passed to this node
}
} // end class MyNode
Add your own namespace to a DxpPage to include your custom tag.
DTD and schema are not requireddxp tags are compiled into server side Objects. They are not xml data that gets sent over a network so there is no need to validate them using a DTD or schema. Intelligent tags should validate their own attributes and children when they create their internal Objects. Forcing the SAX parser to validate according to a DTD or schema when the page is compiled adds more overhead. Parameter attributesYour init() method should check attributes and assign internal references to them. The DxpUtil class has methods to require attributes and create appropriate attribute classes (fixed String, ConstAttribute, RuntimeAttribute, CompositeAttribute). The Using Parameters sample discusses Parameter attributes and Parameter nodes. Here's an example for a hypothetical tag
<xyz:MyNode value="${myobject}" action="magic">
...
</xyz:MyNode>
public class MyNode extends DxpNode {
private Parameter value; // will provide a dynamic value
private String action; // will provide a const value
public void init(String id, Attributes atts) throws DxpException
{
this.id = id; // DxpNode.id provided by linker
value = DxpUtil.getParameterAtt("value", atts, true); // dynamic
action = DxpUtil.getFixedAtt("action", atts, true); // fixed
}
...
} // end MyNode
Parameter nodesParameter nodes are child tags that provide runtime values to their parents. Tags that implement the Parameter interface do most of their work in a getValue() method which can be called directly by their parents. Here's an example from dxp:Random.
public Object getValue(DxpRequest req) throws Exception
{
AuthService authServ = (AuthService) req.getAttribute("AuthService");
String rn = null;
switch(type)
{
case INT:
int n;
if(maxint != null) // if a Parameter attribute was set for maxint
{
n = Integer.parseInt((String) maxint.getValue(req));
n = authServ.random.nextInt(n);
}
else
n = authServ.random.nextInt();
rn = String.valueOf(n);
break;
case LONG:
rn = String.valueOf(authServ.random.nextLong());
break;
case FLOAT:
rn = String.valueOf(authServ.random.nextFloat());
break;
case DOUBLE:
rn = String.valueOf(authServ.random.nextDouble());
break;
default: break;
}
return rn;
}
Parents find Parameter node children in their close() methodWhen a tag's close() method is called by the linker you know that all of it's children have been created and linked. That's when you can find child Parameter nodes that have special significance. Here's an example from dxp:DbAction that finds a child called "stmt", checks the class type and assigns it to a local Parameter.
public void close() throws Exception
{
pStmt = DxpUtil.findParameter("stmt", this, true);
if(pStmt instanceof SqlStmt || pStmt instanceof Cp)
batch = false;
else if(pStmt instanceof SqlStmtArray)
batch = true;
else
throw new DxpException(DxpConst.ILLEGAL_CHILD+pStmt.getClass().getName());
super.close(); // close DxpNode
}
Other things you can do in close()Here is the close() method from dxp:AuthUser.
public void close() throws Exception
{
DxpUtil.findPage(this).setAuthenticator(this);
super.close();
}
Here is the close() method from dxp:ElseIf
public void close() throws Exception
{
If.link(this); // call static method to link me to prev If tag
super.close();
}
See the dxp source code for more examples and ideas. Global ResourcesYour tags have access to classes stored in the ServletContext by the InitServlet including the DbManager, AuthService, DbSessionManager and its easy to write your own. See GobalResource. The framework contains utility classes you might find useful as well. Many are located in these packages. Deploying your tagsA lot of servlet books and docs will tell you to package all your classes in a single .jar or .war file and upload that to your server. This makes sense if you don't change your classes very often or you want to distribute a single app to a large number of customers who don't plan to insert new classes when a bug is found. On a development system it's much easier to keep individual classes in your classpath rather than storing them in a large archive file. When you make a change all you need to do is upload a single class. On your deployment server you may choose to do this as well. |