Piccolo XML processor
This documentation is deprecated! Although the functionality is still in Wandora application, the piccolo_sample_web_app has been removed from Wandora distribution packages.
Piccolo XML processor is a kind of scripting language in xml format that is used to configure Piccolo applications. The language is based and interpreted on Java and you can do nearly anything you could do in normal Java classes.
Each xml element either creates a new instance of some class, retrieves a variable from the symbol table of the processor or invokes a method of an object. Usually element names are completely insignificant and attributes and the structure defines the behaviour. Thus element names are chosen to be somewhat descriptive of what is being done. There are a few exceptions which will be described later.
In following examples xp: prefix refers to http://www.gripstudios.com/xmlparamprocessor xml namespace.
1 <action xp:class="org.wandora.piccolo.actions.ViewTopic"/> 2 <service xp:idref="wandora"/> 3 <logger xp:id="logger" xp:class="org.wandora.piccolo.SimpleLogger"/>
First example creates a new instance of the specified class, the second instance refers to a variable named wandora in the symbol table of the processor but does nothing with that (we will return to this later, why would you actually want to do this). The third example creates a new instance of a logger and stores it in the symbol table with variable name logger. xp:class attribute is used to create new classes, xp:idref to refer to variables in the symbol table and xp:id to store variables in the symbol table. Note that the element names "action", "service" and "logger" do not refer to any class names or variables in symbol table or anything else for that matter.
Using methods, constructors and fields
You can use methods with the xp:method attribute and public varibles of objects with xp:field attribute. You can also use static methods and fields of classes. To do this specify the class with xp:static attribute and then use xp:method to invoke a method or xp:field to access a public variable. For example:
1 <object xp:id="out" xp:static="java.lang.System" xp:field="out"/> 2 <method xp:idref="out" xp:method="println"> 3 <param>Hello World!</param> 4 </method>
This will print "Hello World!" in the standard output. All subelements of method invocation and are processed and passed as parameters for the method. Same is done with constructors when using xp:class attribute to create new instances. In the example one String parameters (line 3) is passed for the method (line 2). Unless nothing else is specified elements will behave as if they contained 'xp:class="java.lang.String"'. When creating new Strings or objects in java.lang package that wrap primitive Java types (such as java.lang.Integer), the contents of the element are read as a string literal instead of subelements being parsed. This string is then given as the only parameter for the constructor. Note that all Java classes that wrap a primitive type have a constructor with a single string parameter. Thus line 3 in the example is in Java 'new java.lang.String("Hello World!")'.
Next example passes two parameters for the constructor of WandoraService.
1 <service xp:id="wandora" xp:class="org.wandora.piccolo.WandoraService"> 2 <param xp:idref="logger"/> 3 <param xp:class="com.gripstudios.piccolo.XMLProperties" > 4 <property><key>wandora.projectfile</key><value>C:/wandora/WEB-INF/classes/base.wpr</value></property> 5 <property><key>wandora.projectfile.autoupdate</key><value>true</value></property> 6 </param> 7 </service>
First parameter is a logger that is retrieved from the symbol table and second parameter is a new instance of XMLProperties class.
If both xp:class and xp:method are present in an element, then the contents of the element are passed to the constructor and the method is called without any parameters. If you want to create a new instance without parameters and call a method with parameters you will have to do it with two elements, first create a new instance and store it in the symbol table and then refer to the stored object and call the method.
Let's look at the lines 4 and 5 of previous example again. According to what has been said so far it would look like on the line 4 a new String is created with two String parameters. But String class does not contain such a constructor. In fact, something completely different happens here. The XMLProperties class implements a certain interface called XMLParamAware. Whenever an object of a class that implements this interface is created, the contents of the element are not parsed and passed to the constructor. Instead a constructor with no parameters is used to create the object and then xmlParamInitialize method of the newly created object is called. This method receives as its parameters the xml element used to create the object and the xml processor itself. The method may then process the contents of the element in any way whatsoever and initialize the object.
Some classes may require a very large, possibly variable, number of parameters and properties to initialize properly. It would be very inconvevient to create constructors for such classes. These kinds of classes should implement XMLParamAware interface. Often classes that are initialized this way still use the xml processor to process at least some subelements individually. For example the class in previous example creates a Properties object that maps keys to values. Each key and value element is processed with the xml processor and could refer to symbol table with xp:idref, create new objects etc. instead of creating simple strings.
This is also one of the exceptions when element names do matter. The class may process the contents of the element in any way and thus can process elements differentely depending on the element name. For example the Piccolo Application class registers services with service element name, parses action map, templates and properties from actionmap, templates and properties elements respectively and adds each object with contextobject element name to the Velocity context.
XML Processor Class Map
The example web application configuration file piccoloconfig.xml has following lines at start:
1 <map xp:idref="this" xp:method="mapClass"> 2 <node>template</node> 3 <class>org.wandora.piccolo.VelocityTemplate</class> 4 </map>
First of all this variable in the symbol table refers to the XMLParamProcessor that is parsing the xml file. It has a method mapClass that takes two String parameters, an element name and a class. This will specify that each element with the given element name in the file (after these lines) will implicitely contain xp:class=secondparameter where secondparameter is the second parameter of the method, that is the class name. The example will thus specify that any element with template element name will be parsed as VelocityTemplate (unless otherwise explicitely specified in the element). This of course is another exception to the rule that element names do not matter.
The default class map contains following mappings:
Using class map and XMLParamAware classes you can hide much of the "code" in the configuration file and make it look like an ordirany xml configuration file. However currently these features are not used as much is possible.