Piccolo XML processor

From WandoraWiki
(Difference between revisions)
Jump to: navigation, search
Line 18: Line 18:
 
  4 </map>
 
  4 </map>
  
Here the method ''mapClass'' of the object in the symbol table with a variable name ''this'' is called (''this'' usually contains the xml processor itself). All subelements are processed and passed as parameters. In this case two ''String'' parameters are passed for the method. Unless nothing else is specified elements will behave as if they contained 'xp:class="java.lang.String"'. Text nodes are also automatically converted to strings. Thus the second line in Java is 'new java.lang.String("template")'. If you only need to pass one ''String'' parameter to a method you may simply put it as a text node inside the element. Here we pass two parameters so we need two xml elements.
+
Here the method ''mapClass'' of the object in the symbol table with a variable name ''this'' is called (''this'' usually contains the xml processor itself). All subelements are processed and passed as parameters for methods or constructors when using ''xp:class'' attribute. In this case two ''String'' parameters are passed for the method. Unless nothing else is specified elements will behave as if they contained 'xp:class="java.lang.String"'. When creating new ''String''s 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. The second line in the example is in Java 'new java.lang.String("template")'.
  
You can also pass parameters for constructors when creating new instances.
+
Next example passes two parameters for the constructor of ''WandoraService''.
  
 
  1 <service xp:id="wandora" xp:class="com.gripstudios.applications.wandora.WandoraService">
 
  1 <service xp:id="wandora" xp:class="com.gripstudios.applications.wandora.WandoraService">
Line 30: Line 30:
 
  7 </service>
 
  7 </service>
  
Here a new instance of ''WandoraService'' is created and two parameters are passed to the constructor. First parameter is a logger that is retrieved from the symbol table and second parameter is the return value of the invocation of ''getProperties'' method of a newly created instance of ''MapParser'' class.
+
First parameter is a logger that is retrieved from the symbol table and second parameter is the return value of the invocation of ''getProperties'' method of a newly created instance of ''MapParser'' class. Let's look at lines 3 to 6 in more detail. Are the parameters on lines 4 and 5 passed for the constructor or the ''getProperties'' method? If both ''xp:class'' and ''xp:method'' are present then the contents of the element are passed to the constructor and the method is called without any parameters. If you wanted to create a new instance without parameters and call a method with parameters you would 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 lines 3 to 6 in more detail. Are the parameters passed for the constructor or the ''getProperties'' method? If both ''xp:class'' and ''xp:method'' are present then the contents of the element are passed to the constructor and the method is called without any parameters. If you wanted to create a new instance without parameters and call a method with parameters you would have to do it with two elements, first create a new instance and store it in symbol table and then refer to the stored object and call the method.
+
  
 
Another peculiarity is the parameters on lines 4 and 5. 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 ''MapParser'' 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.
 
Another peculiarity is the parameters on lines 4 and 5. 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 ''MapParser'' 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 and potentially infinite, 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 could refer to symbol table with ''xp:idref'', create new objects etc. instead of creating simple strings.
+
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 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.
 
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.
 
 
PAGE UNDER CONSTRUCTION
 

Revision as of 12:10, 24 January 2007

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="com.gripstudios.applications.wandora.actions.ViewTopic"/>
2 <service xp:idref="wandora"/>
3 <logger xp:id="logger" xp:class="com.gripstudios.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.

You can also use methods with the xp:method attribute

1 <map xp:idref="this" xp:method="mapClass">
2   <node>template</node>
3   <class>com.gripstudios.piccolo.VelocityTemplate</class>
4 </map>

Here the method mapClass of the object in the symbol table with a variable name this is called (this usually contains the xml processor itself). All subelements are processed and passed as parameters for methods or constructors when using xp:class attribute. In this case two String parameters are passed for the method. 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. The second line in the example is in Java 'new java.lang.String("template")'.

Next example passes two parameters for the constructor of WandoraService.

1 <service xp:id="wandora" xp:class="com.gripstudios.applications.wandora.WandoraService">
2   <param xp:idref="logger"/>
3   <param xp:class="com.gripstudios.piccolo.MapParser" xp:method="getProperties">
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 the return value of the invocation of getProperties method of a newly created instance of MapParser class. Let's look at lines 3 to 6 in more detail. Are the parameters on lines 4 and 5 passed for the constructor or the getProperties method? If both xp:class and xp:method are present then the contents of the element are passed to the constructor and the method is called without any parameters. If you wanted to create a new instance without parameters and call a method with parameters you would 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.

Another peculiarity is the parameters on lines 4 and 5. 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 MapParser 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 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.

Personal tools