How WebMacro Works
Consult the README.html that ships with WebMacro, but the main things you have to get right are:
o Install a Java Virtual Machine and a Servlet engine
o Put webmacro.jar somewhere on your classpath
o Put your servlet engine's .jar file on your classpath
and optionally,
o place a WebMacro.properties file in your classpath to customize your configuration
Introspection Rules
WebMacro follows the JavaBeans specification when performing class analysis, but also extends that specification.
JavaBeans is essentially a set of coding conventions for how to name accessor methods. If you follow those conventions then lots of tools, including WebMacro, will be able to analyze your class to learn what properties it has.
Here are examples of the properties that WebMacro can find:
When resolving $foo.Bar.Baz WebMacro can find:
foo.Bar.Baz -- just field names
foo.Bar.getBaz() -- a field and a JavaBeans accessor
foo.getBar().getBaz() -- simple JavaBeans accessors
foo.get("Bar").getBaz() -- hashtable lookup & accessor
foo.getBar("Baz") -- Baz is a named property of Bar
For more information see PropertyIntrospection.
Using #foreach, WebMacro knows how to iterator over various kinds of objects. For example,
<ul> #foreach $item in $results { <li>$item</li> } </ul>
would generate a bulleted list in HTML where $results is on of the following:
o an array (with any base type, primitive or Object)(文章来源 www.iocblog.net)
o a java.util.Iterator implementation
o a java.util.Enumeration implementation
o a class, such as a Java2 collection, with a method iterator() that returns an Iterator
o a class, such as Vector or Hashtable, with a method elements() that returns an Enumeration
In cases where WebMacro needs to set a property, say $foo.Bar.Baz, it can find methods like these:
foo.Bar.Baz = value -- all fields
foo.Bar.setBaz(value) -- get a field and simple set accessor
foo.getBar().setBaz(value) -- get accessor and set accessor
foo.getBar().put("Baz", value) -- getBar() returns a hashtable?
foo.setBar("Baz", value) -- eg: response.setHeader(header,value)
NOTE: WebMacro can only access public fields and methods. The Java security API prevents WebMacro (or any other package) from gaining access to the private, protected, or package protected data of your objects. If you want WebMacro to see your method, you must make a public method.
Round bracket hack
Template writers may need to access data from a Java object which does not follow the Java beans spec, and does not follow any of the common extensions listed above that WebMacro can introspect.
In these cases you can explicitly name a Java method in a WebMacro template using the round bracket hack:
$foo.name()
$bar.loadValue(10,$arg1,true)
In this case $foo has a badly named accessor: name() should have been called getName(). On the other hand, $bar has a loadValue method which cannot easily be translated to a Java Bean method: it takes three odd arguments.
I call this the round bracket hack because any use of this syntax implies that the template author has some knowledge of the exact Java class which implements $foo and $bar. If instead you could have written $foo.Name the programmer could have provided either a hashtable, or a method with public fields, or a method with public accessors. Since the template writer actually refers to the method by name the programmer winds up being restricted by the template author.
A better solution would be to wrap the non-bean class in a JavaBean? interface. In the future, when WebMacro's introspector is still more powerful than it is now, the round bracket hack may be deprecated and eventually removed.
Concurrency Model: Context-per-thread
Multiple threads can execute a WebMacro template simultaneously: the template is immutable. Once it is loaded and parsed it doesn't change.
Each thread should have its own Context. Think of a Context as the place where each Thread keeps its local data. Since each Context is accessible to only one Thread, it does not need to be locked.
Thus, WebMacro avoids many locks: Templates are not locked because they are immutable. Contexts are not locked because they are accessed by only a single thread each.
You will need synchronization locks in a WebMacro based servlet only when you explicitly share data between multiple threads.
Performance
WebMacro does a lot of work in order to generate your page, so you might wonder whether it's efficient. Here are some answers:
Templates are compiled for efficiency. WebMacro runs a two-phase compile which optomizes out some static content. Unicode character encoding/decoding is done at template compile time and cached for re-use on each request.
Class analysis is cached for efficiency. Analyzing Java classes is very expensive so WebMacro doesn't do that on every request. The first time a class is analyzed WebMacro caches that data for later re-use. It turns out that invoking a reflected method is quite fast, so if you can avoid the expense of the analysis there isn't that much of a hit.
Lock-free design. There are very few synchronization locks in WebMacro, which helps concurrency a lot. Templates are immutable and Contexts are accessed one-per-thread. There are a few locks around various caches but they are constructed to minimize the time a thread must spend inside the monitor, the result being that a high degree of concurrency is possible.
It turns out that for typical applications the cost of your back-end data source will swamp the cost of WebMacro. Generating a page is a fairly efficient operation. You will need to concentrate on optomizing the portions of your application which perform I/O and other more expensive operations--WebMacro will account for only a fraction of the cost of the page.
Extending the Framework
WebMacro loads almost all of its implementation from a configuration file at runtime. You can easily override, extend, or change its behavior by naming your own files in the configuration file instead of the defaults WebMacro ships with.
Here are some of the things you can plug in via configuration file:
o New directives for the script language (pluggable directives)
o What default variables are available in every template (Tools)
o Where templates are loaded from (template path)
o How and when templates are loaded (template provider)
o How long and whether templates are cached
o How the WebMacro language itself is parsed (pluggable parser)
This is what makes WebMacro an extensible framework: almost every aspect of its behavior can be easily overridden.
As the developer of an application framework you can take advantage of these features to customize WebMacro to your particular needs.
Macros
Version 1.1 of WebMacro includes the long-missing #macro directive, which lets you define new directives in WMScript. To the extent possible, macros are evaluated at template compilation time, which enables a number of compile-time optimizations.
If an argument to a macro is an l-value, it will be visible in the macro body as an l-value, meaning that you can pass an l-value into a macro and the macro body will be able to change it. Macros can also reference and change variables in the global context which are not passed in as arguments.
Related to the #macro directive is the #const directive, which behaves much like #set but which defines a compile-time constant. #macro and #const directives can be included with #include, but you must use the #include as macro variant of #include in order to have the macros be accessible from your template.
o Install a Java Virtual Machine and a Servlet engine
o Put webmacro.jar somewhere on your classpath
o Put your servlet engine's .jar file on your classpath
and optionally,
o place a WebMacro.properties file in your classpath to customize your configuration
Introspection Rules
WebMacro follows the JavaBeans specification when performing class analysis, but also extends that specification.
JavaBeans is essentially a set of coding conventions for how to name accessor methods. If you follow those conventions then lots of tools, including WebMacro, will be able to analyze your class to learn what properties it has.
Here are examples of the properties that WebMacro can find:
When resolving $foo.Bar.Baz WebMacro can find:
foo.Bar.Baz -- just field names
foo.Bar.getBaz() -- a field and a JavaBeans accessor
foo.getBar().getBaz() -- simple JavaBeans accessors
foo.get("Bar").getBaz() -- hashtable lookup & accessor
foo.getBar("Baz") -- Baz is a named property of Bar
For more information see PropertyIntrospection.
Using #foreach, WebMacro knows how to iterator over various kinds of objects. For example,
<ul> #foreach $item in $results { <li>$item</li> } </ul>
would generate a bulleted list in HTML where $results is on of the following:
o an array (with any base type, primitive or Object)(文章来源 www.iocblog.net)
o a java.util.Iterator implementation
o a java.util.Enumeration implementation
o a class, such as a Java2 collection, with a method iterator() that returns an Iterator
o a class, such as Vector or Hashtable, with a method elements() that returns an Enumeration
In cases where WebMacro needs to set a property, say $foo.Bar.Baz, it can find methods like these:
foo.Bar.Baz = value -- all fields
foo.Bar.setBaz(value) -- get a field and simple set accessor
foo.getBar().setBaz(value) -- get accessor and set accessor
foo.getBar().put("Baz", value) -- getBar() returns a hashtable?
foo.setBar("Baz", value) -- eg: response.setHeader(header,value)
NOTE: WebMacro can only access public fields and methods. The Java security API prevents WebMacro (or any other package) from gaining access to the private, protected, or package protected data of your objects. If you want WebMacro to see your method, you must make a public method.
Round bracket hack
Template writers may need to access data from a Java object which does not follow the Java beans spec, and does not follow any of the common extensions listed above that WebMacro can introspect.
In these cases you can explicitly name a Java method in a WebMacro template using the round bracket hack:
$foo.name()
$bar.loadValue(10,$arg1,true)
In this case $foo has a badly named accessor: name() should have been called getName(). On the other hand, $bar has a loadValue method which cannot easily be translated to a Java Bean method: it takes three odd arguments.
I call this the round bracket hack because any use of this syntax implies that the template author has some knowledge of the exact Java class which implements $foo and $bar. If instead you could have written $foo.Name the programmer could have provided either a hashtable, or a method with public fields, or a method with public accessors. Since the template writer actually refers to the method by name the programmer winds up being restricted by the template author.
A better solution would be to wrap the non-bean class in a JavaBean? interface. In the future, when WebMacro's introspector is still more powerful than it is now, the round bracket hack may be deprecated and eventually removed.
Concurrency Model: Context-per-thread
Multiple threads can execute a WebMacro template simultaneously: the template is immutable. Once it is loaded and parsed it doesn't change.
Each thread should have its own Context. Think of a Context as the place where each Thread keeps its local data. Since each Context is accessible to only one Thread, it does not need to be locked.
Thus, WebMacro avoids many locks: Templates are not locked because they are immutable. Contexts are not locked because they are accessed by only a single thread each.
You will need synchronization locks in a WebMacro based servlet only when you explicitly share data between multiple threads.
Performance
WebMacro does a lot of work in order to generate your page, so you might wonder whether it's efficient. Here are some answers:
Templates are compiled for efficiency. WebMacro runs a two-phase compile which optomizes out some static content. Unicode character encoding/decoding is done at template compile time and cached for re-use on each request.
Class analysis is cached for efficiency. Analyzing Java classes is very expensive so WebMacro doesn't do that on every request. The first time a class is analyzed WebMacro caches that data for later re-use. It turns out that invoking a reflected method is quite fast, so if you can avoid the expense of the analysis there isn't that much of a hit.
Lock-free design. There are very few synchronization locks in WebMacro, which helps concurrency a lot. Templates are immutable and Contexts are accessed one-per-thread. There are a few locks around various caches but they are constructed to minimize the time a thread must spend inside the monitor, the result being that a high degree of concurrency is possible.
It turns out that for typical applications the cost of your back-end data source will swamp the cost of WebMacro. Generating a page is a fairly efficient operation. You will need to concentrate on optomizing the portions of your application which perform I/O and other more expensive operations--WebMacro will account for only a fraction of the cost of the page.
Extending the Framework
WebMacro loads almost all of its implementation from a configuration file at runtime. You can easily override, extend, or change its behavior by naming your own files in the configuration file instead of the defaults WebMacro ships with.
Here are some of the things you can plug in via configuration file:
o New directives for the script language (pluggable directives)
o What default variables are available in every template (Tools)
o Where templates are loaded from (template path)
o How and when templates are loaded (template provider)
o How long and whether templates are cached
o How the WebMacro language itself is parsed (pluggable parser)
This is what makes WebMacro an extensible framework: almost every aspect of its behavior can be easily overridden.
As the developer of an application framework you can take advantage of these features to customize WebMacro to your particular needs.
Macros
Version 1.1 of WebMacro includes the long-missing #macro directive, which lets you define new directives in WMScript. To the extent possible, macros are evaluated at template compilation time, which enables a number of compile-time optimizations.
If an argument to a macro is an l-value, it will be visible in the macro body as an l-value, meaning that you can pass an l-value into a macro and the macro body will be able to change it. Macros can also reference and change variables in the global context which are not passed in as arguments.
Related to the #macro directive is the #const directive, which behaves much like #set but which defines a compile-time constant. #macro and #const directives can be included with #include, but you must use the #include as macro variant of #include in order to have the macros be accessible from your template.
文章整理:iocblog
版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。