A simple tag without contents
In this example we will create an RXML tag that outputs the company name. By updating the company name in the module, and then reloading the module, the change will occur everywhere that the tag has been used in the site. So this could be one way of implementing a string constant. (Another way would be to define it in an XSLT template, of course.) The module is installed exactly the same way as the Uppercase Tag module from the first example.
Notice the difference in the method queryTagFlags(), where we tell the parser that there should be no contents.
Source code for CompanyName.java
import com.roxen.roxen.*;
import java.util.Map;
public class CompanyNameTag extends Module
implements ParserModule, SimpleTagCaller {
public String info() {
return "RXML empty tag that returns the company name.";
}
public String queryName() {
return "Company Name";
}
public SimpleTagCaller[] querySimpleTagCallers() {
return new SimpleTagCaller[] { this };
}
public String queryTagName() {
return "companyname";
}
public int queryTagFlags() {
return FLAG_EMPTY_ELEMENT;
}
public String tagCalled(String tag,
Map args,
String contents,
RoxenRequest req,
Frame frame) {
return "Roxen Internet Software AB";
}
}
Adding and using an admin variable
To improve the companyname tag, we would like to be able to change the string. One way of doing this is by introducing a variable in the administrative interface. This is accomplished by adding a constructor. There you put tasks to be performed when the class is loaded, for example the defvar() method. More information is in the code comments.
There are a number of constants in the class Module to set the type of the variable. All of these are not yet mapped to Java classes, but they are there for future compatibility. For the moment, we only recommend the use of TYPE_STRING and TYPE_FLAG.
Source code for VariableCompanyNameTag.java
import com.roxen.roxen.*;
import java.util.Map;
public class VariableCompanyNameTag extends Module
implements ParserModule, SimpleTagCaller {
public VariableCompanyNameTag() {
/* Parameters to the defvar function:
String var, Object value, String name, int type, String doc
The parameter name has the format "tabname:label"
If there is no colon, the default tab 'settings' is used */
defvar("companyName", "Roxen IS AB",
"Company Name ", TYPE_STRING,
"Company name - Default value: \"Roxen IS AB\".");
}
public String info() {
return "RXML tag that returns a variable company name.";
}
public String queryName() {
return "Variable Company Name";
}
public SimpleTagCaller[] querySimpleTagCallers() {
return new SimpleTagCaller[] { this };
}
public String queryTagName() {
return "var-companyname";
}
public int queryTagFlags() {
return FLAG_EMPTY_ELEMENT;
}
public String tagCalled(String tag, Map args,
String contents,
RoxenRequest req, Frame frame) {
String company = (String)query("companyName");
if (company != null) return company;
/* else */ return "";
}
}
Addressing variables from other modules
At times you might need to get the value from a variable belonging to another module. You reach other modules by using a provider module. In this example we create a module whose sole purpose is to provide common parameters, where the class is called ParameterProvider. We then show the code lines needed to access the parameter from another module
Source code for ParameterProvider.java
import com.roxen.roxen.*;
public class ParameterProvider
extends Module implements ProviderModule {
/* **************************** *
* Constructor *
* **************************** */
public ParameterProvider () {
defvar("productString", "Roxen CMS", "productString",
TYPE_STRING, "Product name");
}
/* **************************** *
* Methods from Module *
* **************************** */
/** Returns the name of this module */
public String queryName() {
return "Parameter Provider";
}
/** Returns a short description of this module */
public String info() {
return "Contains parameters reachable from other modules.";
}
/* **************************** *
* Methods from ProviderModule *
* **************************** */
/** Returns the identifier of this provider */
public String queryProvides() {
return "commonParameters";
}
}
Code to reach an external variable in ParameterProvider from other modules
Module params = myConfiguration().getProvider("commonParameters");
String product = params.query("productString");
A useful tag showing incoming parameters
To understand the incoming parameters to the tagCalled-function, and for debugging purposes, it can be useful with a module that outputs these parameters. In addition to the previous examples, this module contains one new method:
Source code for JavaDebugLightTag.java
import com.roxen.roxen.*;
import java.util.*;
public class JavaDebugLightTag
extends Module implements ParserModule, SimpleTagCaller {
int callCount;
StringBuffer resp;
/* **************************** *
* Constructor *
* **************************** */
/** The constructor is intially called when the modul is loaded.
For example, register variables for the admin interface */
public JavaDebugLightTag() {
/* parameters to the defvar function:
String var, Object value, String name, int type, String doc
The parameter name has the format "tabname:label"
If no colon is present, default tab 'settings' is used
There are 19 valid types, but here we show use only two:
TYPE_STRING and TYPE_FLAG */
/* The first variable will appear under default tab 'Settings' */
defvar("myString", "Roxen", "myString", TYPE_STRING,
"String admin variable. " +
"Default value: \"Roxen\".");
/* The second variable will appear under a tab called 'Flags'.
A flag has the value "1" when set and null when unset. */
defvar("myFlag", null, "Flags: myFlag", TYPE_FLAG,
"An example admin variable in the form of a flag.");
}
/* **************************** *
* Methods from Module *
* **************************** */
/** Returns the name of this module */
public String queryName() {
return "Java Debug Light Tag";
}
/** Returns a short description of this module */
public String info() {
return "A demo Java module for outputing some parameters.";
}
/** Intial things to do when the module is started.
For example, initiate variables or write to the log */
protected void start() {
callCount = 0;
}
/* **************************** *
* Methods from ParserModule *
* **************************** */
/** Returns one instance of each RXML tag class (SimpleTagCaller)
handled by this parser module. */
public SimpleTagCaller[] querySimpleTagCallers() {
return new SimpleTagCaller[] { this };
}
/* **************************** *
* Methods from SimpleTagCaller *
* **************************** */
/** Returns the name of the tag handled by this tag caller. */
public String queryTagName() {
return "javadebuglight";
}
/** Returns one or more mode flags for this tag caller. */
public int queryTagFlags() {
/* Valid flags: FLAG_NONE, FLAG_EMPTY_ELEMENT,
FLAG_NO_PREFIX, FLAG_PROC_INSTR, FLAG_DONT_PREPARSE,
FLAG_POSTPARSE, FLAG_STREAM_RESULT, FLAG_STREAM_CONTENT,
FLAG_DEBUG */
return FLAG_NONE;
}
/** Evaluates a result for the call to this tag caller. */
public String tagCalled(String tag, Map args, String contents,
RoxenRequest id, Frame frame) {
/* tag - the name of the tag (javadebuglight)
args - all attributes/value-pairs from the start tag
contents - all contents between the start and the end tag
id - the Roxen request object
frame - the RXML parse frame */
callCount++;
resp = new StringBuffer();
/* Class variables */
resp.append("<b>CLASS VARIABLES</b><br/>");
resp.append("Call Count=" + callCount + "<br/>");
/* Element variables */
resp.append("<br/><b>ELEMENT VARIABLES</b><br/>");
resp.append("tag=" + tag + "<br/>");
resp.append("args=" + args + "<br/>");
resp.append("contents=" + contents + "<br/>");
/* Admin variables */
resp.append("<br/><b>ADMIN VARIABLES</b><br/>");
resp.append("myString: " + query("myString") + "<br/>");
if (query("myFlag") != null) {
resp.append("Admin variable 'myFlag' is set " +
"(Value=" + query("myFlag") + ")<br/>");
} else {
resp.append("Admin variable 'myFlag' is unset<br/>");
}
/* URL parameter test */
resp.append("<br/><b>URL PARAMETER TEST</b><br/>");
// Check the URL for parameter ?cmd=save
if (id.variables().containsKey("cmd")) {
if (id.variables().get("cmd").toString().equals("save")){
resp.append("URL contains 'cmd=save' <br/>");
} else {
resp.append("URL parameter 'cmd' is "
+ "something else than 'save'<br/>");
}
} else {
resp.append("URL does not contain parameter 'cmd'<br/>");
}
/* some module class methods */
resp.append("<br/><b>MODULE CLASS METHODS</b><br/>");
resp.append("Internal location: "
+ queryInternalLocation() + "<br/>");
resp.append("Status: " + status() + "<br/>");
/* some client request variables */
resp.append("<br/><b>CLIENT REQUEST VARIABLES</b><br/>");
resp.append("Client IP: " + id.remoteaddr + "<br/>");
resp.append("Raw URL: " + id.rawURL + "<br/>");
resp.append("Request variables: " + id.variables()
+ "<br/>");
resp.append("Remote address: " + id.remoteaddr + "<br/>");
resp.append("Request time: " + new Date(id.time) + "<br/>");
resp.append("<br/>Raw request:<br/>" + id.raw
+ "<br/><br/>");
/* some client request methods */
resp.append("<br/><b>CLIENT REQUEST METHODS</b><br/>");
resp.append("Cookies:<br/>" + id.cookies() + "<br/><br/>");
resp.append("Supported:<br/>" + id.supports() + "<br/>");
/* Evaluation is finished - return the result */
return RoxenLib.parseRXML(resp.toString(), id);
}
}
A module containing more than one class file
So far we have implemented each module as a class file of its own. This is possible, but the preferred way is to install a module as a jar-file, perhaps implementing several tags in one and the same module. As an example we will have one module containing the two tags <uppercase></uppercase> and <companyname/>.
What we need:
We now also have a package structure for our classes. The jar file will be
created in the top directory 'myproject' in this example
Directory and file structure
- myproject (dir)
- classes (dir)
Manifest
- com (dir)
- roxen (dir)
- examples (dir)
JavaTags.class
CompanyNameTag.class
UpperCaseTag.class
Source of Manifest file
Name: Roxen Java RXML tag module
Main-Class: com.roxen.examples.JavaTags
Note!
|
The Manifest file must end with a line feed, which means you must press Enter
at the end of the line defining 'Main Class' before saving the file.
|
In the directory where you have saved the Manifest file, create the JavaTags.jar file by typing the following on the command line.
jar -cvfm ../JavaTags.jar Manifest com
Source of CompanyNameTag.java
package com.roxen.examples;
import com.roxen.roxen.*;
import java.util.Map;
public class CompanyNameTag implements SimpleTagCaller {
public String queryTagName() {
return "companyname";
}
public int queryTagFlags() {
return FLAG_EMPTY_ELEMENT;
}
public String tagCalled(String tag, Map args, String contents,
RoxenRequest req, Frame frame) {
return "Roxen Internet Software AB";
}
}
Source of UpperCaseTag.java
package com.roxen.examples;
import com.roxen.roxen.*;
import java.util.Map;
public class UppercaseTag implements SimpleTagCaller {
public String queryTagName() {
return "uppercase";
}
public int queryTagFlags() {
return FLAG_NONE;
}
public String tagCalled(String tag, Map args, String contents,
RoxenRequest req, Frame frame) {
return contents.toUpperCase();
}
}
Source of JavaTags.java
package com.roxen.examples;
import com.roxen.roxen.*;
import java.util.Map;
public class JavaTags extends Module implements ParserModule {
public String info() {
return "Java module for new RXML tags.";
}
public String queryName() {
return "Java RXML Tags";
}
public SimpleTagCaller[] querySimpleTagCallers() {
SimpleTagCaller[] tagArray = new SimpleTagCaller[2];
tagArray[0] = new CompanyNameTag();
tagArray[1] = new UppercaseTag();
return tagArray;
}
}