Author: Timo Laitinen
Date: 2006-05-28
Contents
1. What Is JIC Language?
JIC Language is an XML vocabulary for defining graphs of Java objects. It provides a descriptive and specialized format for describing the state of a group of Java objects.
XML code written in JIC Language is processed by the JIC Engine, a Java program that interprets the information and creates and initializes the actual Java objects.
Before going into the details of the language, the term initialization is explained more thoroughly.
1.1. Initialization of Java Objects
The term initialization is a process where the state of a Java object is set so that it is ready to be used in an application. Although the object state may change also during its lifetime, every object has some kind of an initialization phase.
The simplest way to initialize an object is to make a constructor call. Necessary parameters are provided via constructor arguments and the object is ready for service after the instantiation. According to good object-oriented principles, an object should we in a valid state after the constructor call.
Single constuctor call is rarely enough, though. In practice the object often needs to be configured further by calling one or more of its methods. In addition, objects may also be retrieved from various factories, and the actual constructor call is hidden. And since objects have dependencies to other objects, the initialization of one Java object requires the initalization of also other objects.
The initialization of a Java object therefore consists of the following steps:
-
Collateral initialization - the initialization of additional objects:
- Argument objects - objects that will be used as arguments to a constructor or method call in the object acquisition phase.
- Helper objects - objects that are used in the initialization of the object and discarded afterwards.
-
Object acquisition - obtaining the instance to be initialized:
- Instantiating the object with a constructor call.
- Invoking a method that yields the object. (call to a factory method, for example)
- (Obtaining the value of a static field.)
-
State refinement - calling various initialization methods of the object.
- Initialization methods have always side-effects and they usually do not return anything.
- For example: setting bean properties.
Some notes:
- The initialization process is recursive - the initialization of one object may require the initialization of other objects.
- There is no single way for object acquisition - both constructor and method invocations are used.
- Full initialization requires also calling various initialization methods after the object has been acquired.
The purpose of the initialization process is to set the parameters of an object. Objects are parameterized because the values of some variables was not known when the code was written. Therefore the purpose of the initialization process is to define the detailed values for the parameters.
Details are usually information that needs to be changed relatively easily. Therefore various configuration files are used for storing the detailed values - configuration files are easier/faster to change than Java code. Example of this is the use of properties files in Java applications.
After the initialization, the object is ready to be used somehow. Usually a reference to the object is given to other objects in the application and the objects start to interact with each other via method calls. The state of the initialized object may change during its lifetime. Sooner or later the object is discarded or the whole application is stopped. The events that occur after the initialization are not in focus here. Regardless of what happens when the object is used, each object has some kind of an initialization phase.
1.2. Purpose of JIC Language
JICE is a tool specialized into the initialization and JIC Language is the XML-based language used for describing the details of the process. JIC Language code can be understood as procedural code. The JIC Engine processes the XML elements much in the order that they appear, so the elements can be thought to be executed. The XML code can be seen as a large patch process that constructs the graph of objects.
The language supports the initialization process presented in the previous chapter fully. JIC Language can be used for both defining a String
and a complex graph of Swing components. No restrictions are placed on the kind of constructors or methods an object has or what interfaces it implements. JIC Language may initialize any kind of Java object.
However, JIC Language may be used only for describing the object state. It is not a general purpose programming language and can not be used for expressing complex logic. Application logic must be put into the Java classes.
Here are some of the advantages of JIC Language over plain-old Java code:
- Easier/faster to change: no compilation required.
- The XML code can be produced/manipulated dynamically with various XML technologies. (also during application lifetime.)
- The XML format is a more descriptive format for representing minor details such as numbers, texts, colors, fonts, etc.
- The XML tree visualizes the structure of the object graph better than Java code.
2. About This Document
This document specifies the syntax and semantics of JIC Language, the XML configuration format of JICE. The document serves both as a tutorial for learning JIC Language and as the specification of the language.
In contrast, the other parts of JICE (i.e. the JIC Engine) and the way JICE could be utilized in real-life applications are not discussed.
2.1. About the Examples
All the examples are manipulating the standard J2SE classes, because the standard Java API is familiar to all Java developers.
However, JIC Language is by no means limited to operating only with the standard Java API. In fact, if JIC Language would be used in a real-life application, the JIC files would manipulate most likely the application classes.
Because the purpose of the examples is to demonstrate the capabilities of the JIC Language, some of them may seem even absurd if viewed as actual configuration files.
3. Overview of JIC Language Syntax
Here is a list of the most significant characteristics of the JIC Language syntax:
-
JIC files are XML files containing JIC Language code. The use of file-suffix
.jic
is encouraged. - JIC Language specifies a common element type called JIC Element. Every XML element in a JIC File is a JIC Element.
-
JIC Language does not have a fixed set of XML elements:
- (In most cases) the author of the file chooses the name of the elements in the same way as a programmer chooses variable names.
- In some situations the name depends on the Java API being manipulated.
- The result is that the element names in a JIC File are always related to the domain of the application being configured.
- Because the element names are not fixed, an exact DTD/schema of the JIC Language can not be defined.
- Every element in a JIC File must belong to the namespace
http://www.jicengine.org/jic/2.1
. -
JIC Language specifies a fixed set of JIC attributes. The attributes define the behaviour and semantics of an element. The attributes are:
-
action
-
args
-
class
-
if
-
instance
-
overridable-by
-
type
-
vars
-
- Actual values such as strings, numbers and booleans are always placed on the CDATA sections of the elements.
- Attributes are used for describing Java-specific things: constructor and method calls, classes, etc.
- Mixed content (elements inside a CDATA section) are not allowed.
- Elements may contain additional attributes, if the attributes belong to a namespace of their own. They can be used for example to store meta-data that makes it easier to manipulate the files with XML tools. The JIC Engine ignores these extra attributes when processing a JIC file.
The syntax adheres to good XML design principles. Elements define the structure of the data, CDATA is used for specifying the data and the attributes are used for meta-data. The format is very verbose - if descriptive element names are used, every string and number has a name that tells something about the meaning of the value. The names of the XML element are always related to the context of the objects being initialized.
The file contains a single JIC Element <message>
that defines the String
"Hello World!":
<message xmlns="http://www.jicengine.org/jic/2.1">Hello World!</message>
In Java code the same thing would be expressed as:
String message = "Hello World!"; return message;
Here is a more complex JIC File. The JIC Element <calendar>
initializes an instance of java.util.GregorianCalendar
and uses several other JIC Elements in the process.
<calendar xmlns="http://www.jicengine.org/jic/2.1" class="java.util.GregorianCalendar" args="year,month,day">
<year>2004</year>
<month>9</month>
<day>9</day>
<lenient>true</lenient>
<timeZone class="java.util.TimeZone">GMT</timeZone>
</calendar>
In Java the same initialization would be expressed as:
int year = 2004; int month = 9; int day = 9; java.util.GregorianCalendar calendar = new java.util.GregorianCalendar(year,month,day); calendar.setLenient(true); calendar.setTimeZone(java.util.TimeZone.getTimeZone("GMT")); return calendar;
4. JIC Elements
4.1. What Are JIC Elements?
JIC Elements are the basic building blocks in JIC Language. JIC Element is an executable unit that performs individual initialization tasks. A JIC Element is capable of:
- initializing a Java object (called element instance)
- calling an initialization method (called action)
- doing both of the above
In the XML file the JIC Elements appear as XML elements - every XML element in a JIC File is a JIC Element.
JIC Elements take advantage of other JIC Elements in performing complex tasks. For example, the initialization of a Java object may be a complex process - the constructor arguments must also be initialized and after construction there may be some initialization methods that must be called. In such cases the initialization is divided into simpler subprocesses that are delegated to other JIC Elements. Complex tasks are therefore executed with the help of many JIC Elements.
The cooperation/delegation relationships of JIC Elements appear as parent-child relationships of the XML elements. A JIC Element uses its child elements in achieving a complex task, and the task of an element is part of a larger task executed by the parent of the element. JIC Elements use their child elements and serve their parent elements.
4.2. Name of a JIC Element
Every JIC Element has a name that is defined by the name of the XML element:
- The name resembles a variable name
- The author of the file may choose the name in the same way a programmer may choose the name of a variable.
- Descriptive names should be used. The guidelines for choosing variable names can be applied.
- (In most cases) the name is used by the parent JIC Element for referring to the element instance of the element (more about this later).
- (In most cases) the name must be a valid Java variable name (
variableName
instead ofvariable-name
orvariable.name
)
Note that the name is used only for identifying the element, it does not define the behaviour of the element (attributes are used for this).
4.3. Element Instance
The object initialized by a JIC Element is referred to as element instance. The attribute instance
is used for specifying the instance. The value of the attribute is a simple Java expression - for example a constructor or a method call - that, when executed, will return the object.
This Java expression is referred to as the constructor of a JIC Element. When a Java object is initialized, the object acquisition step is performed by executing the constructor.
The instance
attribute provides a flexible way for defining how the element instance is obtained. The kind of Java expressions supported are listed on the table below.
expression type | examples |
---|---|
constructor invocation |
new java.util.Date()
|
method call |
out.println()
|
value of a variable |
out
|
value of a static field |
java.lang.System.out
|
(The expression may contain variables that are available in the current context. The contex and the variables are explained more thoroughly later. Most often the variables refer to element instances of the child elements, so there is a child element whose name matches the variable.)
The class of the element instance must always* be defined. This is done with the attribute class
that holds a full class name. The class-information is useful in situations where the class of the instance can not be directly seen from the instance
attribute. The element instance of the element may also be derived from the class
attribute, if the instance
attribute is not specified.
*) the class
attribute may be omitted in simple elements that contain CDATA. In such cases the class is either String
or a primitive such as int
, double
or boolean
.
<calendar class="java.util.Calendar" instance="java.util.Calendar.getInstance()"/>
<string class="java.lang.String" instance="cdata">This is a String</string>
<number class="int" instance="java.lang.Integer.parseInt(cdata)">123</number>
<locale class="java.util.Locale" instance="new java.util.Locale(language,country)">
<language class="java.lang.String" instance="cdata">fi</language>
<country class="java.lang.String" instance="cdata">FI</country>
</locale>
The JIC fragment above resembles the following Java code:
java.util.Date date = new java.util.Date(); java.util.Calendar calendar = java.util.Calendar.getInstance(); String string_ = "This is a String"; int number = java.lang.Integer.parseInt("123"); String language = "fi"; String country = "FI"; java.util.Locale locale = new java.util.Locale(language,country);
JIC Language defines many shortcuts that make it easier to define common types of element instances. Therefore the attribute instance
can be omitted in many cases. The examples above can also be written in the following form:
<calendar class="java.util.Calendar" instance="java.util.Calendar.getInstance()"/>
<string>This is a String</string>
<number>123</number>
<locale class="java.util.Locale">fi_FI</locale>
Element instances and the related attributes are described in more detail in chapter How To Define Element Instances?.
4.4. Action
A JIC Element may also have an action. Action is a Java operation similar to the constructorr that defines the element instance. The action is also executed when the element is processed. However, the return value of action is discarded.
Action is used for calling an initialization method which have side-effects and which do not usually return anything. Actions are therefore utilized in the state refinement. However, actions do not usually call a method of their own element instance. Instead, they often modify the state of the element instance of their parent elements. After the parent element has obtained its element instance, it delivers the instance to child elements, which may modify the state of the instance.
Action is set with the attribute action
and it may hold similar simple Java expressions as the instance
attribute (see JIC Expressions). The action
attribute can be used together with the instance
attribute.
Below is a JIC File where both <entry>
elements execute an action that adds an entry to the java.util.HashMap
instance.
The variable parent
refers to the Map
instance created by the parent element <map>
.
<map xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap">
<entry action="parent.put(key,value)">
<key>key1</key>
<value>value1</value>
</entry>
<entry action="parent.put(key,value)">
<key>key2</key>
<value>value2</value>
</entry>
</map>
In Java the same Map
would be constructed as:
java.util.HashMap map = new java.util.HashMap(); map.put("key1","value1"); map.put("key2","value2"); return map;
The element <lenient>
sets the property lenient
of the java.util.Calendar
instance. The element instance of <lenient>
becomes the value of the property.
<calendar xmlns="http://www.jicengine.org/jic/2.1" class="java.util.Calendar" instance="java.util.Calendar.getInstance()">
<lenient action="parent.setLenient(this)" class="boolean" instance="java.lang.Boolean.valueOf(cdata)">true</lenient>
</calendar>
In most cases the action is a Java expression that starts with "parent."
. Therefore a shortcut is provided. The Map
example above can also be written in the form:
put(key,value)
means parent.put(key,value)
.
<map xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap">
<entry action="put(key,value)">
<key>key1</key>
<value>value1</value>
</entry>
<entry action="put(key,value)">
<key>key2</key>
<value>value2</value>
</entry>
</map>
NOTE: Be aware that the JIC Language and Java differ in the way they interpret a plain method call such as put(key,value)
:
- In Java it means:
this.put(key,value)
- In JIC Language it means:
parent.put(key,value)
The action can also be used for calling static methods.
<system-property>
sets a system property by calling java.lang.System.setProperty
<system-property xmlns="http://www.jicengine.org/jic/2.1" action="java.lang.System.setProperty(name,value)">
<name>example.property</name>
<value>This is just an example</value>
</system-property>
4.5. Variable Elements And Action Elements
Element instance and action are optional - a JIC Element must have either one, or both. The action has a crucial effect on the role of a JIC Element. The purpose of elements with action is to execute the action. Elements that only define an element instance however form a variable that is used by their parent elements.
Elements with action are called action elements and elements without action are called variable elements. The situation is summarized in the following table.
Element role | Has action | Has element instance |
---|---|---|
-ILLEGAL- | - | - |
variable element | - | + |
action element | + | - |
action element | + | + |
Variable elements and action elements differ in the way that they cooperate with their parent elements:
- A variable element:
- Forms a variable:
- the name is the name of the JIC Element
- the value is the element instance.
- The parent element must use the variable for something. For example:
- the variable is used in creating the element instance.
- the variable is used in the action.
- the variable is used to define an element variable inside the parent element.
- The element name must be a valid Java variable name so that it can be used in Java expressions.
- Forms a variable:
- An action element:
- Executes an operation.
- Typically used for:
- Calling of a method of the element instance of the parent, e.g. setting the value of a property.
- Calling a static method.
- The element name has no importance.
- The element instance of an action element can not be referenced outside the element.
4.6. Variables And Contexts
4.6.1. What Are Variables And Contexts?
Variables are objects that can be referenced by name. They are used in the Java operations of attributes instance
and action
.
Most variables are defined by the variable elements. In addition, the JIC Language defines a few built-in variables such as this
, cdata
and parent
, for example.
A context is a namespace that holds a set of variables. The context defines a scope where the variable can be used. A variable must always be bound to a single context. However, because the contexts are nested, a variable may be available in many contexts regardless of this.
Every JIC Element has 3 different contexts:
-
element context: for variables that are available everywhere inside the element:
- [the element context of the parent element]
- + those child variable elements that are marked as element variables with the attribute
vars
.
-
instance context: for variables that are available in the
instance
attribute:- [the element context of the element]
- + those child variable elements that are used in the
instance
attribute. - + built-in variable
cdata
- + built-in variable
parent
-
action context: for variables that are used in the action:
- [the element context of the element]
- + those child variable elements that are used in the
action
attribute. - + built-in variable
this
- + built-in variable
parent
There is also a special root context. The root element of the JIC File has no parent element, but the root context can be thought of as "the element context of the parent of the root element".
The use of variables in the instance
and action
attribute is pretty straight-forward. A variable in the Java expression refers most often to a child element, as already shown in many examples.
Element variables and the use of attribute vars
is presented in chapter How to Use Element Variables?.
4.6.2. How to Resolve the Context of a Variable?
The context of the built-in variables is predetermined. The context of variables that are defined by variable elements is always chosen by the parent element. The method is simple: the parent simply checks whether the variable is used in the attribute instance
, action
or vars
.
The element <print-message>
contains 2 variable elements:
- The variable
date
defined by<date>
is put to instance context - The variable
out
defined by<out>
is put to actioncontext
<print-message xmlns="http://www.jicengine.org/jic/2.1" action="out.println(this)" class="java.lang.String" instance="date.toString()">
<date class="java.util.Date" instance="new java.util.Date()"/>
<out class="java.io.PrintStream" instance="java.lang.System.out"/>
</print-message>
4.6.3. Built-in Variables
JIC Language specifies the names of a few built-in variables:
Name | Refers to | Context |
---|---|---|
parent
|
the element instance of the parent element.
Available if:
|
instance context and action context |
this
|
the element instance of the element itself, if the element has one. | action context |
cdata
|
the String-value of the CDATA section of the element, if the element has one. | instance context |
buildContext
|
An instance of org.jicengine.BuildContext . Always available. |
root context |
*) the JIC Elements are processed in the order that they appear in the JIC File. The Java operation yielding the element instance is executed as soon as all the necessary variable elements have been processed, but not before. Therefore the variable parent
is available only in child elements that appear after the variable elements used in the instance
attribute.
4.6.4. Loose Variable Elements
If the parent can not determine a context for a variable, the variable element that defined it becomes a loose variable element. They are a kind of wildcards that are used for various purposes. By default, a loose variable element is used for setting a bean property: the name of the element defines the property name, and the element instance is the value of the property.
the <lenient>
is a loose variable element. The parent <calendar>
uses it for setting the property lenient
of the java.util.Calendar
instance.
<calendar xmlns="http://www.jicengine.org/jic/2.1" class="java.util.Calendar" instance="java.util.Calendar.getInstance()">
<lenient class="boolean" instance="java.lang.Boolean.valueOf(cdata)">true</lenient>
</calendar>
The same effect would be achieved if the <lenient>
would have the attribute action="parent.setLenient(this)"
.
The way the parent element handles loose variable elements depends on the type of the element. Different JIC Element types have varying policies for loose variable elements. JIC Element types are presented in the section JIC Element Types.
4.7. How JIC Elements Are Executed?
After the JIC Engine has parsed a JIC File, it starts executing the JIC elements. There is only a single root element, which is executed first.
The execution propagates to child elements - the child elements are executed as part of the execution of the parent.
The elements are always executed in the same order that they appear in the JIC file. If one wants to follow the execution by looking at the XML code, each element can be thought to be fully executed after its end tag.
The execution has the following steps:
Step | Description | Initialization phase |
---|---|---|
1 |
Child elements are executed one by one, until all variable elements needed in obtaining the element instance have been encountered. After a variable element has been executed, the respective variable is made available in the appropriate context. |
collateral initialization |
2 |
The element instance is obtained by executing the Java operation set with |
object acquisition |
3 |
Rest of the child elements are executed, again one by one. |
state refinement |
4 |
The action of the element is executed. |
state refinement of the parent |
NOTE: the execution of a JIC Element may be altered if:
- the
if
attribute is set. (see How to Use the if Atribute for Controlling the Execution of a JIC Element) - the JIC Element type of an element is
switch
. (see How to Use the switch Type for Choosing the Element Instance Dynamically. - the JIC Element type of an element is
factory
. (see User-defined Factories. - the element is overridden. (see Build Parameters and Overridings.
4.8. Order of Child Elements
Because the order of the elements has significance, it is recommended that the child elements would always be put in a following order:
- variable elements that are declared as element variables
-
variable elements used in the
instance
attribute - action elements and loose variable elements
-
variable elements used in the
action
attribute
JIC Language does not force this order but the scheme would prohibit most stupid errors like calling an initialization method before the object has been created, etc.
4.9. Summary
A JIC Element is an executable unit capable of initializing a Java object or executing a Java operation. The initialized object is referred to as element instance and the Java operation action. These two capabilities make it possible to initialize all kinds of Java objects.
JIC Elements accomplish complex initialization tasks by working together. Contexts are used for passing necessary object references from element to another.
5. How To Define Element Instances?
This section shows in more detail how the element instance of an element can be defined.
5.1. Primitives
Internally JICE handles every primitive as a corresponding wrapper object - int
is handled as an instance of java.lang.Integer
, etc. The wrapper objects are converted to primitives when needed i.e. when they are used in method calls.
Therefore there is no real difference between primitives and the corresponding wrapper objects. You may use either the primitive type or the wrapper object class in the class
attribute.
5.2. Using CDATA to Define Strings
Elements may access their CDATA via the variable cdata
that contains the String
-value of the CDATA section. The CDATA section makes it possible to define a new String
, which may then be converted to other kinds of Java objects.
Few examples that access CDATA and convert it to other kind of Java objects.
<number class="java.lang.Integer" instance="java.lang.Integer.valueOf(cdata)">12345</number>
<number2 class="double" instance="java.lang.Double.valueOf(cdata)">123.45</number2>
<boolean class="boolean" instance="java.lang.Boolean.valueOf(cdata)">true</boolean>
<url class="java.net.URL" instance="new java.net.URL(cdata)">http://www.sourceforge.net</url>
5.3. CDATA Conversions
Although String
s are common in configuration files, also many other kind of value objets are needed, such as numbers (int
, double
, etc.), booleans, urls, locales, colors, fonts, etc.
There are two kinds of CDATA conversions:
- Class-based CDATA conversions
- The
class
attribute defines what kind of object is created from the CDATA. - Syntax-based CDATA conversions*
- The value of the CDATA itself is used to resolve how the CDATA should be converted.
*) Syntax-based CDATA conversions are available only in JICE 2.1 and later.
In both cases, the instance
attribute is omitted, which reduces the amount of XML code. With syntax-based CDATA conversions, also the class
attribute is omitted.
CDATA Conversions make the use of CDATA more efficient. The String
-value of the CDATA section is automatically converted to certain kinds of objects. The type of object to be instantiated is determined by the class
attribute and the instance
attribute may be omitted.
The previous example can be written without the instance
attribute:
<number class="java.lang.Integer">12345</number>
<number2 class="double">123.45</number2>
<boolean class="boolean">true</boolean>
<url class="java.net.URL">http://www.sourceforge.net</url>
The same in Java:
String string1 = "This is a String"; Integer number = new Integer(12345); double number2 = 123.45; boolean boolean_ = true;
Certain types (String
, int
, double
and boolean
) may be created also without the class
attribute. The example above could be written as:
<number>12345</number>
<number2>123.45</number2>
<boolean>true</boolean>
<url class="java.net.URL">http://www.sourceforge.net</url>
CDATA conversions provide a convenient way to create data-objects that have an unambiguous String-form.
5.3.1. List of Available Class-based CDATA Conversions
All currently available conversions are listed in the following table.
Class | Corresponding instance attribute |
Accepted CDATA |
---|---|---|
boolean
|
java.lang.Boolean.valueOf(cdata)
|
boolean values |
double
|
java.lang.Double.valueOf(cdata)
|
double values |
float
|
java.lang.Float.valueOf(cdata)
|
float values |
int
|
java.lang.Integer.valueOf(cdata)
|
integer values |
long
|
java.lang.Long.valueOf(cdata)
|
long values |
short
|
java.lang.Short.valueOf(cdata)
|
short values |
java.lang.Boolean
|
java.lang.Boolean.valueOf(cdata)
|
boolean values |
java.lang.Double
|
java.lang.Double.valueOf(cdata)
|
double values |
java.lang.Float
|
java.lang.Float.valueOf(cdata)
|
float values |
java.lang.Integer
|
java.lang.Integer.valueOf(cdata)
|
integer values |
java.lang.Long
|
java.lang.Long.valueOf(cdata)
|
long values |
java.lang.Short
|
java.lang.Short.valueOf(cdata)
|
short values |
java.lang.String
|
cdata
|
any value |
java.lang.Class
|
[internal to JICE] |
Full class name such as:
|
java.awt.Color
|
[internal to JICE] |
Color values in both hexadecimal and integer formats: for example 00FF99 or 0,255,127
The alpha channel can also be specified: 00FF9966 or 0,255,127,90 .
|
java.awt.Dimension
|
[internal to JICE] |
Dimension in format width x height
for example 200x100 , 50 x 100 , etc.
|
java.awt.Font
|
java.awt.Font.decode
|
Font values, e.g. Arial-10
|
java.awt.Point
|
[internal to JICE] |
A point in format (x,y)
for example (0,0) , (100,50) , etc.
|
java.math.BigDecimal
|
new java.math.BigDecimal(cdata)
|
A decimal value. |
java.math.BigInteger
|
new java.math.BigInteger(cdata)
|
An integer value. |
java.net.URL
|
new java.net.URL(cdata)
|
An url. |
java.util.Locale
|
[internal to JICE] |
A locale code in format language_country
for example en_US , fi_FI , etc.
|
java.util.TimeZone
|
java.util.TimeZone.getTimeZone(cdata)
|
An id of a timezone. |
org.jicengine.io.Resource
|
[internal to JICE] |
Accepts a file path that is relative to the current JIC file. The format is specified by |
5.3.2. Class-based CDATA Conversion Examples
<color class="java.awt.Color">255,255,255</color>
java.awt.Color color = new java.awt.Color(255,255,255);
java.awt.Dimension dimension = new java.awt.Dimension(150,50);
java.awt.Font font = java.awt.Font.decode("Arial-10");
java.awt.Point point = new java.awt.Point(0,0);
java.net.URL url = new java.net.URL("http://www.google.com");
java.util.Locale locale = new java.util.Locale("en","US");
java.util.TimeZone timeZone = java.util.TimeZone.getTimeZone("GMT");
5.3.3. Syntax-based CDATA Conversions
If the class
attribute is omitted, the syntax of the CDATA is examined to find out how it should be processed:
Syntax | Resulting object | Examples |
---|---|---|
an integer value (only digits, optionally starting with the minus sign) |
int , as parsed by the java.lang.Integer.valueOf
|
<value1>123</value1>
<value2>0</value2> <value3>-12356</value3> |
a decimal value (only digits with the integer and decimal part, optionally starting with the minus sign) |
double , as parsed by the java.lang.Double.valueOf
|
<value1>12.3</value1>
<value2>0.0</value2> <value3>-123.56789</value3> |
boolean i.e. true or false
|
boolean , as parsed by the java.lang.Boolean.valueOf
|
<value1>true</value1>
<value2>false</value2> |
any other kind of value |
java.lang.String
|
<string1>this is a String</string1>
<string2>12.4.2006</string2> <string3>properties.property</string3> |
If you want to create a String
"-1234"
, "true"
, etc., specify the attribute class="String"
. This disables the syntax-based CDATA conversion.
(NOTE: JICE 2.0.x did not support syntax-based CDATA conversions. if the class
was omitted, the result was always a String
.)
5.4. How to Invoke Constructors?
An object is instantiated by using the new
operator to invoke the constructor. The constructor invocation can be defined in the instance
attribute.
However, because object instantiation is a very common way to define the element instace, a shortcut is provided. The value of the instance
attribute can be derived from the class
attribute and the instance
attribute can be left out. This saves the author from e.g. writing the class name twice.
In case the invoked constructor requires parameters, the necessary constructor arguments are defined with the attribute args
that holds a list of arguments.
The instance
attribute can be omitted.
<map class="java.util.HashMap"/>
The JIC fragment above is equal to this:
<map class="java.util.HashMap" instance="new java.util.HashMap()"/>
The args
attribute specifies the constructor arguments:
<initialSize>20</initialSize>
</map>
<dateFormat class="java.text.SimpleDateFormat" args="pattern,locale">
<pattern>yyyy-MM-dd</pattern>
<locale class="java.util.Locale">fi_FI</locale>
</dateFormat>
The JIC fragment above is equal to this:
<initialSize class="int">20</initialSize>
</map>
<dateFormat class="java.text.SimpleDateFormat" instance="new java.text.SimpleDateFormat(pattern,locale)">
<pattern>yyyy-MM-dd</pattern>
<locale class="java.util.Locale">fi_FI</locale>
</dateFormat>
5.5. How to Obtain the Return-value of a Method Call?
The element instance may also be obtained via method call. For example, the object is retrieved from a static factory, which means that the static factory must be called. There are also many situations when an instance method needs to be called in order to obtain the object.
The attribute instance
is used for defining the method call. There are no shortcuts provided. Below are a few examples.
Note that the attribute args
is used only for defining the arguments of a constructor call. Arguments to a method call are defined inside the instance
attribute.
An instance of java.util.Calendar
is obtained with the method java.util.Calendar.getInstance(TimeZone timeZone)
<calendar xmlns="http://www.jicengine.org/jic/2.1" class="java.util.Calendar" instance="java.util.Calendar.getInstance(timeZone)">
<timeZone class="java.util.TimeZone">Europe/Helsinki</timeZone>
</calendar>
The same in Java:
String id = "Europe/Helsinki"; java.util.TimeZone timeZone = java.util.TimeZone.getTimeZone(id); java.util.Calendar calendar = java.util.Calendar.getInstance(timeZone); return calendar;
The element instance of the <formattedDate>
is the result of formatting the java.util.Date
instance with the java.text.DateFormat
.
<formattedDate xmlns="http://www.jicengine.org/jic/2.1" class="java.lang.String" instance="dateFormat.format(date)">
<dateFormat class="java.text.DateFormat" instance="java.text.DateFormat.getInstance()"/>
<date class="java.util.Date"/>
</formattedDate>
The same in Java:
java.text.DateFormat dateFormat = java.text.DateFormat.getInstance(); java.util.Date date = new java.util.Date(); String formattedDate = dateFormat.format(date); return formattedDate;
5.6. How to Obtain the Value of a Static Field?
The attribute instance
may also be used for retrieving the value of a static field:
<out xmlns="http://www.jicengine.org/jic/2.1" class="java.io.PrintStream" instance="java.lang.System.out"/>
java.io.PrintStream out = java.lang.System.out;
<position xmlns="http://www.jicengine.org/jic/2.1" class="java.lang.String" instance="java.awt.BorderLayout.NORTH"/>
String position = java.awt.BorderLayout.NORTH;
5.7. How to Obtain the Value of a Variable?
The element instance of an element may also simply be the value of a variable.
<innerMessage>This is the message</innerMessage>
</message>
String innerMessage = "This is the message"; String message = innerMessage;
5.8. How to Create Arrays?
The instance
attribute can also be used for creating arrays. However, the JIC Element type 'array' provides a much more efficient way to both create and populate arrays. See Type array.
<array xmlns="http://www.jicengine.org/jic/2.1" class="java.lang.String[]" instance="new java.lang.String[size]">
<size class="int">0</size>
</array>
6. How to Use Element Variables?
As mentioned earlier, every JIC Element has 3 contexts that each hold a set of variables:
- instance context
- action context
- element context
The instance context and action context are very restricted - they are accessed only from the instance
and action
attributes, respectively.
Variables in the element context however have a wider scope: they can be accessed everywhere inside the JIC Element. This includes:
- The
action
andinstance
attributes of the element. - The
action
andinstance
attribute of every element inside the element.
The variables in the element context are called element variables. They can be thought of as a sort of global variables inside the element which can be used by many child elements.
The attribute vars
is used to declare the element variables of an element. The attribute holds a comma-separated list of variables that identifies which child variable elements define the element variables.
The <birthdays>
initializes a java.util.Map
that contains mappings from a persons name (as String
) to their birthdays (as java.util.Date
)
The <parseFormat>
defines a java.text.DateFormat
that is used for parsing String-values into java.util.Date
-objects.
The <date>
elements may use the variable parseFormat
because it is defined as an element variable in <birthdays>
.
<birthdays xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap" vars="parseFormat">
<parseFormat class="java.text.SimpleDateFormat" args="cdata">yyyy-MM-dd</parseFormat>
<birthday action="put(person,date)">
<person>Britney Spears</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1981-12-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Christina Aguilera</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1980-12-18</date>
</birthday>
<birthday action="put(person,date)">
<person>Shakira</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1977-02-02</date>
</birthday>
</birthdays>
In Java the same kind of Map
would be constructed as:
java.text.SimpleDateFormat parseFormat = new java.text.SimpleDateFormat("yyyy-MM-dd"); java.util.HashMap birthdays = new java.util.HashMap(); birthdays.put("Britney Spears", parseFormat.parse("1981-12-02")); birthdays.put("Christina Aguilera", parseFormat.parse("1980-12-18")); birthdays.put("Shakira", parseFormat.parse("1977-02-02")); return birthdays;
Local variables always override element variables.
The birthday of Justin Timberlake is parsed with a different java.text.DateFormat
object. The local variable parseFormat
overrides the element variable with the same name.
<birthdays xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap" vars="parseFormat">
<parseFormat class="java.text.SimpleDateFormat" args="cdata">yyyy-MM-dd</parseFormat>
<birthday action="put(person,date)">
<person>Britney Spears</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1981-12-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Christina Aguilera</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1980-12-18</date>
</birthday>
<birthday action="put(person,date)">
<person>Shakira</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1977-02-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Justin Timberlake</person>
<date class="java.util.Date" instance="parseFormat.parse(dateString)">
<dateString>31.01.1981</dateString>
<parseFormat class="java.text.SimpleDateFormat" args="cdata">dd.MM.yyyy</parseFormat>
</date>
</birthday>
</birthdays>
In Java the same kind of Map
would be constructed as:
java.text.SimpleDateFormat parseFormat = new java.text.SimpleDateFormat("yyyy-MM-dd"); java.util.HashMap birthdays = new java.util.HashMap(); birthdays.put("Britney Spears", parseFormat.parse("1981-12-02")); birthdays.put("Christina Aguilera", parseFormat.parse("1980-12-18")); birthdays.put("Shakira", parseFormat.parse("1977-02-02")); java.text.SimpleDateFormat parseFormat2 = new java.text.SimpleDateFormat("dd.MM.yyyy"); birthdays.put("Justin Timberlake", parseFormat2.parse("31.01.1981")); return birthdays;
7. JIC Element Types
7.1. What Are JIC Element Types?
The type of a JIC Element is used to fine-tune the behaviour of the element. In most cases the type makes it easier to initialize a certain kind of object.
JIC Language defines 10 different JIC element types:
Type | Purpose |
---|---|
bean
|
The default type. Makes it easier to set bean properties. |
array
|
Makes it easier to create and populate an array. |
collection
|
Makes it easier to create and populate a java.util.Collection instance. |
list
|
Makes it easier to create and populate a java.util.List instance. |
map
|
Makes it easier to create and populate a java.util.Map instance. |
container
|
Makes it easier to define element variables. Used often as the type of the root element. |
constant-of
|
Alternative way to access constants (i.e. static fields) |
switch/1
|
A switch structure that makes it possible to select the element instance of an element dynamically from a set of alternatives. |
factory/x
|
Used for defining a factory, kind of a function that is defined and used in JIC Files. |
cdata-converter/1
|
Used for defining a custom CDATA conversion in a JIC File. |
(Note: JIC Element types are not to be confused with the categories action elements and variable elements. A JIC Element is either an action element or a variable element depending on whether it has an action or not. The JIC Element type is defined by the attribute type
.)
The advantage of JIC Element types comes from the way they treat loose variable elements: each type has a different policy that gives the loose variable elements a meaningful purpose.
In most cases the loose variable elements are used for modifying the element instance of the element. The same would be achieved by defining the action
attribute of the child elements, but the JIC Element types make it possible to leave the action
attribute out. Therefore they reduce the amount of code needed to specify certain things.
The types switch/1
and factory/x
are special because they provide functionality that can not be implemented with basic language features.
7.2. JIC Element Types and Loose Variable Elements
The following table lists the policies that different JIC Element types use for loose variable elements.
Type | Policy | Advantage |
---|---|---|
bean
|
Uses a loose variable element for setting a bean property with the same name. | The attribute action="parent.setXXX(this)" can be omitted from the child elements that set properties. |
array
|
Creates an array and puts every loose variable element into the array. | Populating an array becomes very easy. |
collection
|
Adds the element instance of every loose variable element into the collection. | The attribute action="parent.add(this)" can be omitted from the child elements that define list elements. |
list
|
Adds the element instance of every loose variable element into the list. | The attribute action="parent.add(this)" can be omitted from the child elements that define list elements. |
map
|
Puts the element instance of every loose variable element into the Map . The name of the element is used as the key. |
The attribute action="parent.put(name,value)" can be omitted from the child elements that define map entries. |
container
|
Creates an element variable from each loose variable element. | No need to list every element variable in the vars attribute if there are many variables. |
constant-of
|
Child elements not allowed, only CDATA. | Alternative way to access constants (i.e. static fields) |
switch/1
|
Uses loose variable elements as cases. One case is selected by a criteria when the element is executed. | Makes it possible to define the element instance of an element dynamically. |
factory/x
|
May contain a single loose variable element that defines what the factory returns. | Makes it possible to define a factory (a kind of a function) in a JIC File. |
cdata-converter/1
|
May contain one loose variable element that defines the result of the CDATA conversion. | Makes it possible to define a custom CDATA conversion in a JIC File. |
The type of a JIC Element is set with the attribute type
, which holds the name of the type. Default value of the attribute is bean
.
The following sections show how the JIC Element types are used.
7.3. Type bean
(the default)
The bean
type makes it easier to set bean-like properties i.e. call setXXX()-methods. This is all it does - it does not by any means require that the initialized object is a pure bean or prohibit the invocation of other kinds of methods.
<window>
defines an instance of javax.swing.JFrame
that contains a single JLabel
.
Various elements have an action
attribute that sets a property.
<window xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JFrame" args="title">
<title>This is a JFrame</title>
<contentPane action="" class="javax.swing.JComponent" instance="parent.getContentPane()">
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>This is a JLabel</text>
<horizontalAlignment action="setHorizontalAlignment(this)" class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font action="setFont(this)" class="java.awt.Font">Arial-bold-16</font>
</label>
<opaque action="setOpaque(this)">true</opaque>
<background action="setBackground(this)" class="java.awt.Color">200,90,90</background>
</contentPane>
<size action="setSize(this)" class="java.awt.Dimension">200x200</size>
<location action="setLocation(this)" class="java.awt.Point">(300,100)</location>
<defaultCloseOperation action="setDefaultCloseOperation(this)" class="int" instance="javax.swing.JFrame.DISPOSE_ON_CLOSE"/>
<visible action="setVisible(this)">true</visible>
</window>
(Note: <contentPane>
has an empty action
attribute because no action needs to be executed, but we don't want the parent <window>
to handle the <contentPane>
as a variable element either.)
The same <window>
can be constructed also without many action
attributes that were present in the previous example.
All the same properties are still set because of the way the bean
type handles loose variable elements.
Because bean
is the default type, we don't have to use the type
attribute.
<window xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JFrame" args="title">
<title>This is a JFrame</title>
<contentPane action="" class="javax.swing.JComponent" instance="parent.getContentPane()">
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>This is a JLabel</text>
<horizontalAlignment class="int" type="constant-of(javax.swing.SwingConstants)">CENTER</horizontalAlignment>
<font class="java.awt.Font">Arial-bold-16</font>
</label>
<opaque>true</opaque>
<background class="java.awt.Color">99ccff</background>
</contentPane>
<size class="java.awt.Dimension">200x200</size>
<location class="java.awt.Point">(300,100)</location>
<defaultCloseOperation class="int" type="constant-of(javax.swing.JFrame)">DISPOSE_ON_CLOSE</defaultCloseOperation>
<visible>true</visible>
</window>
7.4. Type array
Arrays would be very tedious to initialize without the type array
. Every array element would have to be added with the method java.lang.reflect.Array.set(Object array, int index, Object value)
.
Fortunately, the type array
makes it quite straightforward to define an array.
<array>
initializes an array of String
-objects. Every child element of <array>
is a loose variable element that are made into array elements. The names of the elements have no significance.
The array
type creates automatically an array of correct size. The instance
attribute needs not to be defined.
<array xmlns="http://www.jicengine.org/jic/2.1" class="java.lang.String[]" type="array">
<e>Element 1</e>
<e>Element 2</e>
<e>Element 3</e>
<e class="String">4.45</e>
</array>
Primitive arrays are created with the same procedure.
<array xmlns="http://www.jicengine.org/jic/2.1" class="int[]" type="array">
<one class="int">1</one>
<two class="int">2</two>
<three class="int">3</three>
<four class="int">4</four>
</array>
7.5. Type collection
collection
type makes it easier to populate a collection.
Every collection - list, set, etc. - may be defined also without the collection
type, but it requires that every element must have an action
that adds the element to the collection.
With collection
type, the action
attributs of the child elements may be omitted. Every loose child variable is added to the collection. The examples below demonstrates this.
Every child element has the same kind of action
attribute.
(int
-values can be added to the set because they are automatically converted to java.lang.Integers
)
<set xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashSet">
<e action="add(this)" class="int">1</e>
<e action="add(this)" class="int">2</e>
<e action="add(this)" class="int">3</e>
<e action="add(this)" class="int">4</e>
</set>
<collection xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashSet" type="collection">
<e class="int">1</e>
<e class="int">2</e>
<e class="int">3</e>
<e class="int">4</e>
</collection>
(type collection
is available in JICE 2.0.2 and later releases.)
7.6. Type list
The list
type behaves like the more general collection
, except that the element instance must implement the java.util.List
interface.
<list xmlns="http://www.jicengine.org/jic/2.1" class="java.util.ArrayList" type="list">
<e>1</e>
<e class="int">2</e>
<e>-3344</e>
<e class="int">-4</e>
</list>
7.7. Type map
The map
type makes it easy to populate a java.util.Map
in situations where the keys are Strings and valid XML element names.
map
type handles every loose variable element as an entry in the map. The name of the element becomes the key (as a String
) and the element instance becomes the value.
The map
type is useful in only cases where the keys are appropriate. If other kinds of keys need to be used, the Map
can always be created and populated manually.
<map xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap" type="map">
<entry action="put(key,value)">
<key>background.color</key>
<value class="java.awt.Color">0099CC</value>
</entry>
<entry action="put(key,value)">
<key>foreground.color</key>
<value class="java.awt.Color">000000</value>
</entry>
</map>
<map xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap" type="map">
<background.color class="java.awt.Color">0099CC</background.color>
<foreground.color class="java.awt.Color">000000</foreground.color>
</map>
7.8. Type container
The container
type is useful as the type of the root element in large JIC Files. An element variable is created from every loose variable element, and the scope of the variables is the whole document. Therefore every loose variable element directly under the root element becomes sort of a "global object", which can then be referred to by other elements.
The same could be achieved without the container
type, but then every element variable would have to be listed in the vars
attribute.
The type container
is also useful in making the XML tree in a JIC File flatter. A very deep tree is hard to read, but the file may be easier to understand if it is chopped to smaller units. The same phenomena occurs in Java code: it is considered bad if a single Java method contains lots of code. Therefore the code is devided into multiple smaller methods.
The following file defines a JFrame
that dispalys the current time.
<window xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JFrame" args="title">
<title>Clock</title>
<contentPane action="" class="javax.swing.JComponent" instance="parent.getContentPane()">
<north action="add(this,location)" class="javax.swing.JPanel">
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>The Current Date Is:</text>
<font class="java.awt.Font">Arial-bold-16</font>
</label>
<location class="java.lang.String" instance="java.awt.BorderLayout.NORTH"/>
</north>
<center action="add(this,location)" class="javax.swing.JPanel">
<layout class="java.awt.FlowLayout" args="align">
<align class="int" instance="java.awt.FlowLayout.CENTER"/>
</layout>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text class="java.lang.String" instance="dateFormat.format(currentDate)">
<dateFormat class="java.text.SimpleDateFormat" args="pattern">
<pattern>dd.MM.yyyy HH:mm:ss</pattern>
</dateFormat>
<currentDate class="java.util.Date"/>
</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text class="java.lang.String" instance="timeZone.getID()">
<timeZone class="java.util.TimeZone" instance="java.util.TimeZone.getDefault()"/>
</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<location class="java.lang.String" instance="java.awt.BorderLayout.CENTER"/>
</center>
</contentPane>
<size class="java.awt.Dimension">200x150</size>
<location class="java.awt.Point">(300,100)</location>
<defaultCloseOperation class="int" instance="javax.swing.JFrame.DISPOSE_ON_CLOSE"/>
<visible>true</visible>
</window>
The result looks something like this:
The file below initializes a similar JFrame
than the previous example, but the file is flattened to smaller object definitions.
The <window>
automatically declares the element variables dateFormat
, currentDate
, currentDateLabel
, currentTimeZoneLabel
, northPanel
and centerPanel
from the respective loose variable elements.
The same would be achieved if the <window>
would contain the attribute vars="dateFormat, currentDate, currentDateLabel, currentTimeZoneLabel, northPanel, centerPanel"
.
<windowContainer xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JFrame" type="container" instance="window">
<dateFormat class="java.text.SimpleDateFormat" args="pattern">
<pattern>dd.MM.yyyy HH:mm:ss</pattern>
</dateFormat>
<currentDate class="java.util.Date"/>
<currentDateLabel class="javax.swing.JLabel" args="text">
<text class="java.lang.String" instance="dateFormat.format(currentDate)"/>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</currentDateLabel>
<currentTimeZoneLabel class="javax.swing.JLabel" args="text">
<text class="java.lang.String" instance="timeZone.getID()">
<timeZone class="java.util.TimeZone" instance="java.util.TimeZone.getDefault()"/>
</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</currentTimeZoneLabel>
<northPanel class="javax.swing.JPanel">
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>The Current Date Is:</text>
<font class="java.awt.Font">Arial-bold-16</font>
</label>
</northPanel>
<centerPanel class="javax.swing.JPanel">
<layout class="java.awt.FlowLayout" args="align">
<align class="int" instance="java.awt.FlowLayout.CENTER"/>
</layout>
<label action="add(currentDateLabel)"/>
<label action="add(currentTimeZoneLabel)"/>
</centerPanel>
<window class="javax.swing.JFrame" args="title">
<title>Clock</title>
<contentPane action="" class="javax.swing.JComponent" instance="parent.getContentPane()">
<north action="add(northPanel,location)">
<location class="java.lang.String" instance="java.awt.BorderLayout.NORTH"/>
</north>
<center action="add(centerPanel,location)">
<location class="java.lang.String" instance="java.awt.BorderLayout.CENTER"/>
</center>
</contentPane>
<size class="java.awt.Dimension">200x150</size>
<location class="java.awt.Point">(300,100)</location>
<defaultCloseOperation class="int" instance="javax.swing.JFrame.DISPOSE_ON_CLOSE"/>
<visible>true</visible>
</window>
</windowContainer>
7.9. Type constant-of
The type constant-of/1
provides an alternative method for accessing constants i.e. static fields.
The following example demonstrates the two ways for accessing constants.
<constants xmlns="http://www.jicengine.org/jic/2.1" type="container" class="java.lang.String" instance="message">
<message>This demonstrates how to use the 'constant-of' type.</message>
<position1 class="String" instance="java.awt.BorderLayout.CENTER"/>
<position2 class="String" type="constant-of(java.awt.BorderLayout)">CENTER</position2>
<align1 class="int" instance="java.awt.FlowLayout.LEFT"/>
<align2 class="int" type="constant-of(java.awt.FlowLayout)">LEFT</align2>
<action1 class="int" instance="javax.swing.JFrame.DISPOSE_ON_CLOSE"/>
<action2 class="int" type="constant-of(javax.swing.JFrame)">DISPOSE_ON_CLOSE</action2>
</constants>
The differences are cosmetic. constant-of
allows the value - the name of the constant - to be put into the CDATA section. If the value needs to be changed, only the CDATA section needs to be modified. This way the modification of a constant value is done the same way as String
, int
, boolean
, etc. values are modified.
7.10. Type switch
The type switch/1
is defined in section How to Use the switch Type for Choosing the Element Instance Dynamically
7.11. Type factory
The type factory/x
is defined in section User-defined Factories
7.12. Type cdata-converter
The type cdata-converter/1
is defined in section User-defined CDATA Conversions
8. How to Use the if
Atribute for Controlling the Execution of a JIC Element
8.1. Attribute if
The attribute if
is used to control whether a JIC Element is executed or not.
The attribute holds a JIC expression that is evaluated before the element. In case the expression evaluates to false
, the element is not executed. The result is the same as removing the element from the JIC File. If the expression evaluates to true
or the if
attribute is not set, the element is executed normally.
The if
attribute is associated only with a single JIC Element. It resembles therefore a single if
block in Java. It can not be used for constructing if-else
or if-elseif-else
like structures. See XXX (switch)
<container>
has an element variable doDebug
that is used for determining whether the <print-message>
is executed.
The value of doDebug
is true
, so the message will appear in System.out
when the file is processed.
<container xmlns="http://www.jicengine.org/jic/2.1" action="" vars="doDebug">
<doDebug class="boolean">true</doDebug>
<print-message if="doDebug" action="this.println(message)" class="java.io.PrintStream" instance="java.lang.System.out">
<message>JIC File executed</message>
</print-message>
</container>
The example corresponds to Java code:
boolean doDebug = true; if( doDebug ){ String message = "JIC File executed"; System.out.println(message); } return;
8.2. Uses for if
The effect of not executing a JIC Element is the same as removing the corresponding XML element (and its contents) from the JIC File.
Therefore the attribute if
should only be used in elements that are not required in the execution of other elements. For example, removing an action elements does not usually cause the execution of the parent element to fail. However, removing a variable element may break the parent as one variable is missing.
The table below lists cases where if can be used.
Element | Purpose of if
|
---|---|
action elements |
if controls whether the action is executed or not. |
loose variable elements |
Many loose variable elements are used for executing an operation. E.g.
In such a case the |
other variable elements |
A local variable element may override an outer element variable. Using
The use of |
Note that the expressions inside an unexecuted element are not evaluated. Hence the validity of the expressions is not verified completely. For example the use of non-existing methods or variables is not checked.
Expressions are always parsed, however, so the most trivial syntax errors and illegal class names will be encountered even if an element is not executed.
8.3. Expressions in the if
attribute
The if
attribute is evaluated before the execution of the element is started. The expression is executed in a context of its own, which consists of:
- [the element context of the parent element]
- + the variable
parent
Note that none of the element instances that are inside the element can be referenced from the if
attribute. Even the variable this
can not be used.
Otherwise any valid JIC expression may be used in the if
attribute. The return value of the expression is interpreted as follows:
Return value | Result |
---|---|
a boolean (or a java.lang.Boolean ) |
true or false
|
null
|
false
|
other Java objects |
true
|
Java APIs contain various methods where the return value null
implies some kind of an error. This information may be utilized in the if
attribute, because null
is interpreted as false
.
The !
operator may be used for negating the result. It works also with the "null or non-null" type of tests.
Operators such as =
, <
, >
, &&
and ||
are currently NOT supported.
The following JIC File sets the system property example.property
only if it hasn't been previously set.
<system-property xmlns="http://www.jicengine.org/jic/2.1" action="" type="container">
<propertyName>example.property</propertyName>
<propertyValue>Example value</propertyValue>
<set if="!java.lang.System.getProperty(propertyName)" action="java.lang.System.setProperty(propertyName,propertyValue)"/>
</system-property>
The corresponding Java code is:
String propertyName = "example.property"; String propertyValue = "Example value"; if( System.getProperty(propertyName) != null ){ System.setProperty(propertyName,propertyValue); } return;
9. How to Use the switch
Type for Choosing the Element Instance Dynamically
9.1. Type switch/1
The JIC Element type switch
makes it possible to select the element instance of an element from a set by some criteria. It resembles the switch
structure in Java language.
The switch
type handles every loose variable element as a case. When an element of type switch
is executed, one of the cases is selected and the element instance of the selected element becomes the element instance of the switch element.
The correct case is selected by comparing the names of the case elements with the switch variable. The element whose name equals with the String
value of the variable is selected.
The switch
type operates therefore on Strings
, whereas in Java the switch
structure is based on int
values.
The <text>
is a switch
that has three cases: <fi>
, <en>
and <sv>
. The variable language
is the switch variable.
The <language>
defines the value of the switch variable. The default value is "en"
, but the default can be overridden with a build parameter named lang
. (For more info on build parameters, see Build Parameters and Overridings)
When <text>
is executed, it compares the names of elements <fi>
, <en>
and <sv>
with the value of the variable language
. The first match is chosen, and the element instance of the chosen element becomes the element instance of <text>
.
<button xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JButton" args="text" vars="text">
<text class="java.lang.String" type="switch(language)">
<language overridable-by="lang">en</language>
<fi>Paina minua!</fi>
<en>Click me!</en>
<sv>Tryck mig!</sv>
</text>
</button>
If the build parameter lang
is not provided, the String
"Click me!" becomes the button text. If the parameter is defined but the value does not match with any of the cases, the execution of the <text>
will fail.
The example corresponds to Java code:
String text; String language = "en"; if ( << param "lang" is defined >> ){ language = << value of param "lang" >>; } if (language.equals("fi")){ text = "Paina minua!"; } else if (language.equals("en")){ text = "Click me!"; } else if (language.equals("sv")){ text = "Tryck mig!"; } else { throw new Exception("no match"); } javax.swing.JButton button = new javax.swing.JButton(text); return button;
The switch
type is a genuine switch in the sense that it executes only a single case element - the ones that are not chosen are ignored.
The instance
or args
attributes can not be used with switch
, because the switch already defines how the element instance of the element will obtained.
9.2. How to Define the Default Case?
A case named default
specifies a default case that will be chosen if none of the other cases match.
This example initializes a localized DateFormat
object. If the language does not match, the DateFormat
defined by <default>
will be chosen.
<dateFormat xmlns="http://www.jicengine.org/jic/2.1" class="java.text.DateFormat" type="switch(language)">
<language overridable-by="lang">en</language>
<fi class="java.text.SimpleDateFormat" args="pattern">
<pattern>dd.MM.yyyy</pattern>
<timeZone class="java.util.TimeZone">Europe/Helsinki</timeZone>
</fi>
<en class="java.text.SimpleDateFormat" args="pattern">
<pattern>MM/dd/yy</pattern>
<timeZone class="java.util.TimeZone">America/New_York</timeZone>
</en>
<default class="java.text.SimpleDateFormat" args="pattern">
<pattern>yyyy-MM-dd</pattern>
<timeZone class="java.util.TimeZone">GMT</timeZone>
</default>
</dateFormat>
The example corresponds to Java code:
java.text.DateFormat dateFormat; String language = "en"; if ( << param "lang" is defined >> ){ language = << value of param "lang" >>; } if (language.equals("fi")){ dateFormat = new java.text.SimpleDateFormat("dd.MM.yyyy"); dateFormat.setTimeZone(java.util.TimeZone.getTimeZone("Europe/Helsinki")); } else if (language.equals("en")){ dateFormat = new java.text.SimpleDateFormat("MM/dd/yy"); dateFormat.setTimeZone(java.util.TimeZone.getTimeZone("America/New_York")); } else { dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd"); dateFormat.setTimeZone(java.util.TimeZone.getTimeZone("GMT")); } return dateFormat;
9.3. Limitations
The type switch
is very limited in its capabilities as is also the switch
structure in Java. The criteria for choosing a case is based on Strings
. In addition, the String
must be a valid XML element name.
If more complex logic is needed for choosing the element instance of an element, the logic must be put into a Java class or method which is then used from the JIC File.
10. User-defined Factories
10.1. What Are User-defined Factories?
Factories are kind of functions that are defined and used in JIC Files. On JIC Element creates the factory, which may then be called by other JIC Elements.
Factories have parameters and they can return a Java object. Various JIC Elements may call a factory much like they would call a Java method.
The JIC Element type factory
is used for defining a new factory. The element that defines a factory is referred to as a factory element. The element has a child element defines what the factory returns.
A factory may be called from the instance
attribute with the syntax jic::factory-name(parameters)
.
The factory toUrl
receives a String
and transforms it into a java.net.URL
.
<test xmlns="http://www.jicengine.org/jic/2.1" class="java.net.URL" instance="url">
<toUrl type="factory(java.lang.String location)">
<url class="java.net.URL" args="location"/>
</toUrl>
<url class="java.net.URL" instance="jic::toUrl(cdata)">http://www.google.com</url>
</test>
(note: JIC Language already has a cdata conversion for java.net.URLs so the above factory is not really needed.)
10.2. When to Use Factories?
Factories are useful in situations where multiple similar objects need to be initialized with slightly varying properties. If the configuration of a single object requires 10 lines of JIC Language code, defining many such objects increases the size of the JIC File rapidly. A factory can define the common properties in the objects, and the code needed to configure a single object is reduced.
Note that the same could be achieved by creating a new Java method or class. But there are situations when the nature of the common properties does not belong to Java classes.
The JIC File below initializes a JFrame
that looks something like this:
The configuration of the 7 JLabels
makes the file quite long as each label requires 5 lines:
<window xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JFrame" args="title">
<title>Tip of the Day</title>
<contentPane action="" class="javax.swing.JComponent" instance="parent.getContentPane()">
<northPanel action="add(this,location)" class="javax.swing.JPanel">
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>JIC Element types:</text>
<font class="java.awt.Font">Arial-bold-16</font>
</label>
<location class="java.lang.String" instance="java.awt.BorderLayout.NORTH"/>
</northPanel>
<centerPanel action="add(this,location)" class="javax.swing.JPanel">
<layout class="java.awt.GridLayout" args="rows,cols">
<rows>7</rows>
<cols>1</cols>
</layout>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>bean</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>array</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>list</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>map</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>container</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>switch</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>factory</text>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</label>
<location class="java.lang.String" instance="java.awt.BorderLayout.CENTER"/>
</centerPanel>
</contentPane>
<size class="java.awt.Dimension">200x250</size>
<location class="java.awt.Point">(300,100)</location>
<defaultCloseOperation class="int" instance="javax.swing.JFrame.DISPOSE_ON_CLOSE"/>
<visible>true</visible>
</window>
The only thing different in the JLabel
objects is the label text. With the help of the factory createLabel(java.lang.String text)
, the configuration of the labels is greatly simplified.
<window xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JFrame" args="title">
<title>Tip of the Day</title>
<contentPane action="" class="javax.swing.JComponent" instance="parent.getContentPane()">
<northPanel action="add(this,location)" class="javax.swing.JPanel">
<label action="add(this)" class="javax.swing.JLabel" args="text">
<text>JIC Element types:</text>
<font class="java.awt.Font">Arial-bold-16</font>
</label>
<location class="java.lang.String" instance="java.awt.BorderLayout.NORTH"/>
</northPanel>
<centerPanel action="add(this,location)" class="javax.swing.JPanel">
<layout class="java.awt.GridLayout" args="rows,cols">
<rows>7</rows>
<cols>1</cols>
</layout>
<createLabel type="factory(java.lang.String text)">
<result class="javax.swing.JLabel" args="text">
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</result>
</createLabel>
<label action="add(this)" class="javax.swing.JLabel" instance="jic::createLabel(cdata)">bean</label>
<label action="add(this)" class="javax.swing.JLabel" instance="jic::createLabel(cdata)">array</label>
<label action="add(this)" class="javax.swing.JLabel" instance="jic::createLabel(cdata)">list</label>
<label action="add(this)" class="javax.swing.JLabel" instance="jic::createLabel(cdata)">map</label>
<label action="add(this)" class="javax.swing.JLabel" instance="jic::createLabel(cdata)">container</label>
<label action="add(this)" class="javax.swing.JLabel" instance="jic::createLabel(cdata)">switch</label>
<label action="add(this)" class="javax.swing.JLabel" instance="jic::createLabel(cdata)">factory</label>
<location class="java.lang.String" instance="java.awt.BorderLayout.CENTER"/>
</centerPanel>
</contentPane>
<size class="java.awt.Dimension">200x250</size>
<location class="java.awt.Point">(300,100)</location>
<defaultCloseOperation class="int" instance="javax.swing.JFrame.DISPOSE_ON_CLOSE"/>
<visible>true</visible>
</window>
The factory defines the horizontal alignment and the font of the labels. These properties are typical details that are closer to configuration than application logic. It is therefore feasible to use a factory and define them in a JIC File instead of creating e.g. a subclass of JLabel
which is center aligned and has the proper font by default.
10.3. Type factory/x
Here are the characteristics of the factory
type:
- The name of the factory element defines the name of the factory
- The parameters are defined in the
type
attribute in format:factory(class1 name1, class2 name2, ...)
. For example:-
type="factory()"
-
type="factory(java.lang.String text)"
-
type="factory(java.lang.String text, int number)"
-
- The action of the element is preset to an operation that registers the factory when executed.
- The
action
attribute may therefore not be used.
- The
- The factory element must contain a single loose variable element that defines what the factory returns.
- The element is not executed immediately after it has been processed - it is executed only when the factory is called.
- The element has access to the factory parameters and also other variables that belong to the element context of the parent element.
- The factory element must not contain other elements.
10.4. How to Use Element Variables within Factories?
In addition to the factory parameters and the element instances defined inside the factory, also outer element variables may used in the factory.
The following example demonstrates this.
This example defines labels for every weekday. The labels are returned in an array of JLabel
instances. The label texts (weekdays) are fetched from a ResourceBundle
.
The properties in the ResourceBundle
are defined in two files based on the locale:
Locale en_US
|
Locale fi_FI
|
label.day1 = Monday label.day2 = Tuesday label.day3 = Wednesday label.day4 = Thursday label.day5 = Friday label.day6 = Saturday label.day7 = Sunday |
label.day1 = Maanantai label.day2 = Tiistai label.day3 = Keskiviikko label.day4 = Torstai label.day5 = Perjantai label.day6 = Lauantai label.day7 = Sunnuntai |
In the JIC File the element <bundle>
obtains a ResourceBundle
by locale. The bundle is available as the element variable bundle
.
<createLabel>
defines a factory that creates JLabel
objects. The factory takes a resource bundle key as a parameter. The parameter is used for fetching a localized text for the created JLabel
from the ResourceBundle
.
<labels>
initializes the array that contains the labels.
<container xmlns="http://www.jicengine.org/jic/2.1" class="javax.swing.JLabel[]" instance="labels" vars="bundle">
<bundle class="java.util.ResourceBundle" instance="java.util.ResourceBundle.getBundle(name,locale)">
<name>factory_localized-weekdays</name>
<locale class="java.util.Locale" overridable-by="locale">en_US</locale>
</bundle>
<createLabel type="factory(java.lang.String key)">
<result class="javax.swing.JLabel" args="text">
<text class="java.lang.String" instance="bundle.getString(key)"/>
<horizontalAlignment class="int" instance="javax.swing.SwingConstants.CENTER"/>
<font class="java.awt.Font">Arial-italic-14</font>
</result>
</createLabel>
<labels class="javax.swing.JLabel[]" type="array">
<label class="javax.swing.JLabel" instance="jic::createLabel(cdata)">label.day1</label>
<label class="javax.swing.JLabel" instance="jic::createLabel(cdata)">label.day2</label>
<label class="javax.swing.JLabel" instance="jic::createLabel(cdata)">label.day3</label>
<label class="javax.swing.JLabel" instance="jic::createLabel(cdata)">label.day4</label>
<label class="javax.swing.JLabel" instance="jic::createLabel(cdata)">label.day5</label>
<label class="javax.swing.JLabel" instance="jic::createLabel(cdata)">label.day6</label>
<label class="javax.swing.JLabel" instance="jic::createLabel(cdata)">label.day7</label>
</labels>
</container>
Note that only a single ResourceBundle
instance is created. The same instance is used every time the factory is called.
11. User-defined CDATA Conversions
11.1. What Are User-defined CDATA Conversions
New class-based CDATA conversions may be defined in the JIC File. User-defined CDATA conversions are special factories that are identified by the target class instead of name and that always receive one parameter - the CDATA value of the element.
User-defined CDATA conversions are defined with the element type cdata-converter/1
, which is similar to factory/x
. The target class is given as a parameter for the type.
JIC Language does not have a CDATA conversion for java.util.Dates
, because the date formats for defining dates vary so much. If dates need to be created in a JIC file, the java.text.DateFormat
used for parsing the dates could be defined first and then used for parsing the dates:
<birthdays xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap" vars="parseFormat">
<parseFormat class="java.text.SimpleDateFormat" args="cdata">yyyy-MM-dd</parseFormat>
<birthday action="put(person,date)">
<person>Britney Spears</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1981-12-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Christina Aguilera</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1980-12-18</date>
</birthday>
<birthday action="put(person,date)">
<person>Shakira</person>
<date class="java.util.Date" instance="parseFormat.parse(cdata)">1977-02-02</date>
</birthday>
</birthdays>
The same could be achieved by using a factory, although the factory does not provide much advantages in this case:
<birthdays xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap">
<parseDate type="factory(java.lang.String dateString)">
<date class="java.util.Date" instance="parseFormat.parse(dateString)">
<parseFormat class="java.text.SimpleDateFormat" args="cdata">yyyy-MM-dd</parseFormat>
</date>
</parseDate>
<birthday action="put(person,date)">
<person>Britney Spears</person>
<date class="java.util.Date" instance="jic::parseDate(cdata)">1981-12-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Christina Aguilera</person>
<date class="java.util.Date" instance="jic::parseDate(cdata)">1980-12-18</date>
</birthday>
<birthday action="put(person,date)">
<person>Shakira</person>
<date class="java.util.Date" instance="jic::parseDate(cdata)">1977-02-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Justin Timberlake</person>
<date class="java.util.Date" instance="jic::parseDate(cdata)">1981-01-31</date>
</birthday>
</birthdays>
With a user-defined CDATA conversion, though, the code for creating a java.util.Date
is reduced:
<birthdays xmlns="http://www.jicengine.org/jic/2.1" class="java.util.HashMap">
<toDate type="cdata-converter(java.util.Date)">
<date class="java.util.Date" instance="parseFormat.parse(cdata)">
<parseFormat class="java.text.SimpleDateFormat" args="cdata">yyyy-MM-dd</parseFormat>
</date>
</toDate>
<birthday action="put(person,date)">
<person>Britney Spears</person>
<date class="java.util.Date">1981-12-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Christina Aguilera</person>
<date class="java.util.Date">1980-12-18</date>
</birthday>
<birthday action="put(person,date)">
<person>Shakira</person>
<date class="java.util.Date">1977-02-02</date>
</birthday>
<birthday action="put(person,date)">
<person>Justin Timberlake</person>
<date class="java.util.Date">1981-01-31</date>
</birthday>
</birthdays>
11.2. When to Use User-defined CDATA Conversions?
user-defined CDATA conversions are useful in situations where have some application-specific objects that have a clear string-form. In these cases the user-defined CDATA conversions make it easier to define instances of these classes.
11.3. The type cdata-converter/1
The type cdata-converter/1
behaves much like the type factory/x
. Characteristics:
- There is only one argument: the class name of the target class.
- Registering to CDATA conversions for the same class is not allowed.
- Overriding a default CDATA conversion of the JIC Language is not allowed.
- The JIC element of type
cdata-converter/1
may have only one child element, which will be the result of the conversion. - The variable
cdata
refers to the CDATA to be converted.- if the child has its own CDATA, this CDATA will override the CDATA given as a parameter and the conversion will not work.
- The actual result of the CDATA conversion may be a subclass of the class that the conversion is registered to. So you can register a conversion for an interface and specify the actual implementation class only in the element that defines the CDATA conversion.
(Type cdata-converter
is available in JICE 2.1.2 and later.)
12. Build Parameters and Overridings
12.1. What Are Build Parameters?
A JIC File may receive build parameters. They are named Java objects that are given to the JIC engine at "runtime" i.e. when the JIC engine processes the JIC file. Build parameters can be used in the JIC File together with the Java objects initialized by the JIC elements.
A build parameter can be used in two ways:
- The parameter can override the element instance of a JIC Element. This kind of a parameter is an optional one and the JIC Element being overridden provides the default value.
- The parameter value can be retrieved explicitly. This kind of parameter is an obligatory parameter: the processing of the JIC File will fail if the parameter isn't present.
The details on how to provide build parameters to a JIC File are defined by the JIC Engine. See JIC Engine.
12.2. Overriding Element Instances: Attribute overridable-by
The element instance of any JIC Element can be declared to be overridable by a certain build parameter. This means that the element instance of the element serves as a default value. It is used if the parameter is not available. If the parameter exists, the parameter value will become the element instance of the element.
The attribute overridable-by
declares that the element instance may be overridden. The value of the attribute is the name of the build parameter that is capable of overriding the instance.
The element <locale> is overridable by a build parameter locale
.
<numberFormat xmlns="http://www.jicengine.org/jic/2.1" class="java.text.NumberFormat" instance="java.text.NumberFormat.getIntegerInstance(locale)">
<locale class="java.util.Locale" overridable-by="locale">en_US</locale>
</numberFormat>
Note that only elements marked overridable can be overridden with build parameters. There is no support for overriding any element in a JIC File.
12.3. Effects of Overriding
If an element is overridden, the element is will not be executed normally:
- Only variable elements that are used in the action will be executed.
- all other inner variable elements are skipped.
- all inner action elements are skipped.
- The element instance of the element is not created.
- The action of the element will be executed normally. If the action refers to the variable
this
, it will refer to the value of the overriding parameter.
If the build parameter message
is present, the element <inner-action-element>
will never be executed.
If the parameter is not available, the message "inner-action-element executed"
will appear in System.out
.
<message xmlns="http://www.jicengine.org/jic/2.1" class="java.lang.String" instance="defaultValue" overridable-by="message">
<defaultValue>Hello World</defaultValue>
<inner-action-element action="out.println(debug)">
<debug>inner-action-element executed</debug>
<out class="java.io.PrintStream" instance="java.lang.System.out"/>
</inner-action-element>
</message>
12.4. How to Access Build Parameters Directly?
The value of a build parameter can be retrieved also directly. The instance
attribute is used for this with a little peculiar syntax.
The element instance of <element>
will be an int
defined by the build parameter meaningOfLife
.
The prefix param::
is followed by the name of the parameter. The parameter name does not have to adhere to the restrictions of Java variable names.
The parameter name may contain also characters that are not allowed within Java variables.
<element2 class="int" instance="param::meaning-of-life"/>
13. How to Access File Resources from JIC Files?
One way to access file resources from JIC Files is to use the Java IO API in the same way as any API is used in JIC Language. For example, a java.io.File
object may be created and read easily.
However, JIC Language provides also tools for locating various file resources with paths relative to the current JIC File. The resource model in the package org.jicengine.io
is used for this.
By a resource we mean any kind of data that is read through the java.io.InputStream
or java.io.Reader
classes. The resource could be a file resource that is read with java.io.FileInputStream
or it could be web resource that is read through a java.net.URL
. See the package org.jicengine.io
for more details.
The org.jicengine.io
package does not need to be used if the resources are located through absolute paths or urls. But if relative paths needs to be used, the package provides nice tools for this.
The element type resource is used for locating resources relative to the current JIC File. For an example, lets say that we have the following file structure:
dir/ |_ subdir/ | |_ file2.properties | |_ example.jic |_ file1.properties
In the example.jic
, the Java properties file file1.properties
can be read with the following JIC script:
<inputStream action="load(inputStream)" class="java.io.InputStream" instance="resource.getInputStream()">
<resource class="org.jicengine.io.Resource">file1.properties</resource>
</inputStream>
</properties>
The example script does approximately the following:
- Element <properties> creates an empty
java.util.Properties
instance. - The element <resource> creates an instance of
org.jicengine.io.Resource
that points to the properties file. - The element <inputStream> obtains a
java.io.InputStream
instance from the <resource> element and loads the properties by calling theload
method.
Of course, the other properties file may be read with the same fashion.
<inputStream action="load(this)" class="java.io.InputStream" instance="resource.getInputStream()">
<resource class="org.jicengine.io.Resource">subdir/file2.properties</resource>
</inputStream>
</properties>
The org.jicengine.io
package is a good tool for reading resources. If you want to only resolve the url to the resource instead of reading it, most, but not all, of the implementations of the org.jicengine.io.Resource
interface support also this.
14. How to Use Multiple JIC Files Together?
In a larger application there often rises a need to manipulate multipe JIC Files and use them modularily together. Here are a few examples of possible scenarios:
- Using one JIC File as input to another JIC file
- Extending a JIC File: One file serves as a default or template, which is extended by others.
- Generating JIC Files from other XML formats
JICE provides currently only the basic tools for processing single JIC Files.
14.1. How to Use the Output of a JIC File as Input to Another JIC file?
JIC Files can be chained together: the output of one JIC File can be used as input to another. This can be done in two ways:
- The output is delivered to the other JIC file as a build-parameter.
- The second JIC file asks the JIC Engine to parse the other JIC file and retrieves the output directly.
Both ways are explained in more detail below.
Suppose that we have a file DateFormat.jic
that yields a java.text.DateFormat
instance:
<dateFormat xmlns="http://www.jicengine.org/jic/2.1" class="java.text.SimpleDateFormat" args="pattern,locale">
<pattern>dd.MM.yyyy HH:mm:ss z</pattern>
<locale class="java.util.Locale" args="language,country">
<language>fi</language>
<country>FI</country>
</locale>
</dateFormat>
We want to use the DateFormat
in the file formatDate.jic
:
<dateFormat class="java.text.DateFormat" instance="param::dateFormat"/>
<date class="java.util.Date"/>
</formattedDate>
We would chain the two files in the application code:
import org.jicengine.io.*; import org.jicengine.*; import java.io.*; // .... try { // locate the two files Resource file1 = new FileResource(new File("DateFormat.jic")); Resource file2 = new FileResource(new File("formatDate.jic")); // process the first file DateFormat dateFormat = (DateFormat) JICEngine.build(file1); // construct parameters for the second file Map buildParams = new HashMap(); buildParams.put("dateFormat", dateFormat); // process the second file String formattedDate = (String) JICEngine.build(file2, buildParams); } catch (Exception e){ // handle exception }
We may also implement the chaining in the second JIC file. So we would modify the file formatDate.jic
in the above example into this:
<dateFormat class="java.text.DateFormat" instance="org.jicengine.JICEngine.build(file)">
<file class="org.jicengine.io.Resource">DateFormat.jic</file>
</dateFormat>
<date class="java.util.Date"/>
</formattedDate>
14.2. Extending a JIC File
This refers to a situation where a JIC File needs to be modified slightly in order to derive a new configuration from it. There are many similar configurations, and there is a need to specify the common features in a single place, which is then extended.
Currently, two approaches can be used:
Technique | Pros & Cons |
---|---|
The other files provide overridings to the general file. | Simple. However, only elements marked overridable can be overridden. |
Modify the JIC File with XSLT | Any element can be modified. Requires however that the programmer knows XSLT. It may also be confusing that some of the configuration is written in JIC Language and the other in XSLT. |
An example of the XSLT transformation is given below.
The following kind of file is extended:
<formattedDate xmlns="http://www.jicengine.org/jic/2.1" class="java.lang.String" instance="dateFormat.format(date)">
<dateFormat class="java.text.SimpleDateFormat" args="pattern,locale">
<pattern>dd.MM.yyyy HH:mm:ss z</pattern>
<locale class="java.util.Locale" args="language,country">
<language>fi</language>
<country>FI</country>
</locale>
</dateFormat>
<date class="java.util.Date"/>
</formattedDate>
The following XSLT modifies the dateformat pattern.
The default template in the the XSLT copies every node to the result tree as is.
However, the one template matches the element j:formattedDate/j:dateFormat/j:pattern
and replaces it with a new element.
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:j="http://www.jicengine.org/jic/2.1" xmlns="http://www.jicengine.org/jic/2.1" version="1.0" exclude-result-prefixes="j" > <xsl:output method="xml" version="1.0" encoding="ISO-8859-1" omit-xml-declaration="no" indent="yes" /> <!-- =========================== override a single element =========================== --> <xsl:template match="j:formattedDate/j:dateFormat/j:pattern"> <pattern>yyyy-MM-dd HH:mm:ss z</pattern> </xsl:template> <!-- also other overridings could be specified here with similar templates. --> <!-- this copies every other node to the result tree. --> <xsl:template match="@*|node()" priority="-100"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
The XSL transformation results in the following JIC File where the <pattern>
element has a different value.
<formattedDate xmlns="http://www.jicengine.org/jic/2.1" class="java.lang.String" instance="dateFormat.format(date)">
<dateFormat class="java.text.SimpleDateFormat" args="pattern,locale">
<pattern>yyyy-MM-dd HH:mm:ss z</pattern>
<locale class="java.util.Locale" args="language,country">
<language>fi</language>
<country>FI</country>
</locale>
</dateFormat>
<date class="java.util.Date"/>
</formattedDate>
14.3. Generating JIC Files from other XML formats
JIC Language can be used in creating a mapping from any XML format to Java.
An application could for example specify a custom XML format, which is then converted to JIC Language code with XSLT and processed.
15. JIC Attribute Definitions
Attribute | Purpose |
---|---|
action="JIC expression"
|
Sets the action of the element. |
args="variable list"
|
Specifies constructor arguments. |
class="full.class.name"
|
Defines the class of the element instance of the element. |
if="JIC expression"
|
Defines an operation that determines whether the element is executed or not. |
instance="JIC expression"
|
Defines the operation that yields the element instance of the element. |
overridable-by="parameterName"
|
Makes the element instance overridable by an external parameter. |
type="typeIdentifier"
|
Sets the JIC element type of the element. |
vars="variable list"
|
Defines the element variables of the element. |
15.1. action="JIC expression"
Effect | Sets the action of the element. |
---|---|
Use |
Optional. Any element could be equipped with an action. The use of action does not depend on any other attribute.
|
Values |
In addition, the use of the actor
this is enough:
Also, an empty value gives the element an action that, when executed, doesn't really do anything:
Other examples:
|
15.2. args="variable list"
Effect |
Specifies constructor arguments given to the constructor in situations where the |
---|---|
Use | Optional. Can not be used with the instance attribute. |
Values |
A comma-separated list of variables. Any value that could be written inside the braces in a constructor invocation is valid. For example:
|
Example |
<locale
class="java.util.Locale"
args="language,country">
<language>fi</language> <country>FI</country> </locale> is the same as: <locale
class="java.util.Locale"
instance="new java.util.Locale(language,country)">
<language>fi</language> <country>FI</country> </locale> |
15.3. class="full.class.name"
Effect |
States that the element has an element instance and signals the type of the instance. The attribute has two roles:
|
---|---|
Use |
Required in elements that have an element instance.
Only exceptions are simple elements that have CDATA. The |
Values |
Note: Array types are defined with the same syntax as in Java source:
Note: Inner classes are defined in a format that includes the |
15.4. if="JIC expression"
Effect | Controls whether the element is executed or not. Defines an expression that, if evaluates to false , hinders the element from being executed. |
---|---|
Use |
Optional. Any element may have a if attribute. Does not depend on other attributes.
|
Values |
Any JIC Expression (see JIC Expressions)
The none of the element instances inside the element can be referenced from the |
15.5. instance="JIC expression"
Effect | Defines how the element instance of the element is obtained. The value is a Java operation that, when executed, yields the object. |
---|---|
Use |
Used in elements that have an element instance.
The instance can be omitted if the element instance is obtained through a constructor invocation.
|
Values |
Any JIC expression may be used (see JIC Expressions). The expression is executed in the instance context of the element.
The expression should return an object, since Examples:
|
15.6. overridable-by="parameterName"
Effect | Declares that the element instance is overridable by a build parameter. See the section on build parameters and overridings for more details. |
---|---|
Optionality | Optional. Can be used only if the element has an element instance. |
Values |
The name of the overriding build parameter. NOTE: currently, a JIC file could contain two overridable elements with the same identifier i.e. the same build parameter would override multiple elements, if the Java classes of the elements are the same. Don't yet know whether this would be a good thing or not so try to avoid that. |
15.7. type="typeIdentifier"
Effect | Sets the JIC element type of the element. |
---|---|
Optionality | Optional |
Value |
|
15.8. vars="variable list"
Effect | Defines which of the inner variable elements become element variables. |
---|---|
Use | Optional. |
Values |
A comma-separated list of variable names that must match to the child variable elements of the element. |
16. JIC Expressions
A JIC expression may consists of the following expressions:
- variable - the name of a valid Java variable name
-
method invocation
- static:
<full.class.Name>.method(<parameters>)
, or - instance:
<variable>.method(<parameters>)
, where -
<parameters>
is a comma separated list of variables
- static:
-
new operation
- class:
new <full.class.Name>(<parameters>)
, or - array:
new <full.class.Name>[<size>]
- class:
-
static field
- format
<full.class.Name>.<field name>
- format
-
negation
-
!<expression>
, where -
<expression>
may be any other JIC Expression
-
-
build parameter expression
-
param::<parameter name>
-
-
factory call
-
jic::<factory name>(<parameters>)
-
The class names of inner classes contain the $
character. Instead of full.class.Name.InnerClass
, the format full.class.Name$InnerClass
must be used.