Download Chapt 15 WebMacro

Document related concepts
no text concepts found
Transcript
WebMacro
a template language
Webmacro: what is it?
• WebMacro is a page generator which
introspects ordinary Java objects to extract their
properties and drop them into a template.
Typically you use it to create an HTML view of a
set of Java objects. You can use WebMacro
under a Java servlet to generate HTML, XML, or
other formats in response to web requests. You
can also use WebMacro offline to generate the
same pages from a batch processing job:
WebMacro is not tied to the servlet API.
How does a programmer use it?
• Here is the simplest way:
WebMacro wm = new WebMacro(); // probably just once in your servlet
FastWriter out = new FastWriter(outStream); // create a FastWriter
Context c = wm.getContext(); // do this every request
c.put("query", queryString); // put ordinary Java object: a string?
Result[] res = ...; // some data: maybe search results?
c.put("results", res); // put complex objects in here too!
Template t = wm.getTemplate("search.view");
t.write(out, context);
The key steps here are:
• Put your application data into a Context
• Load a Template
• write: WebMacro applies your Context to the Template
tutorial continued
• The most important point is that the
objects you put into the context are plain,
vanilla, ordinary Java objects: WebMacro
performs class analysis to figure out how
to extract the data required by the
Template. This means that as a
programmer you concentrate on writing
ordinary Java objects, without regard to
how they are rendered in the final page
view. Your code looks and feels like what it
is: pure Java code.
How does a template writer use it?
• Given the servlet code above, an over-simplified
"search.view" might look like this:
<html>
<head><title>Search Results</title></head> <body>
<h1>Here are the results for $query:</h1> <table>
#foreach $result in $results {
<tr><td>$result.Number</td>
<td><a
href="$result.Link">$result.Name</a></td></tr> }
</table> </body></html>
• The main point is that this is pretty much
ordinary HTML.
How/why use it, continued
• There is an extremely simple scripting code here, but the logic
relates to how the page is going to look. Nothing in the template
describes how the search result was obtained, nor is there any
business logic here. The logic on the page is page logic. WebMacro
would replace $queryString with the string you added to the context.
Next it would loop through the Result array looking at each element
and working out how to extract the properties "Name", "Number",
and "Link" from whatever sort of objects happened to be in the array.
• WebMacro follows the JavaBeans standard when performing this
analysis, and might find a result.Number field, a result.getLink()
method, and perhaps might resort to result.get("Name") to extract
the Name field. The particulars would depend on the actual Java
definition of the Result class.
installation
• webmacro can be obtained at
www.webmacro.org
• This routes you to a page at sourceforge and
you select a mirror site to download from .
• Webmacro is about 3meg for a platform
independent zip.
• A link for setting up webmacro:
http://www.webmacro.org/QuickStart
• Since text documentation for webmacro is pretty
old, I’ve pasted in some documentation that
comes with the distribution.
from current webmacro distribution file:
configuring examples.txt
•
•
TOMCAT CONFIGURATION ( tested v5.5.9)
=========================================
•
There are two ways to get started:
•
a) Copy the files from release/examples/* to a webapps directory named
wm/. This
will create a working web application. You will want to manually copy jar files
to the WEB-INF/lib folder such as webmacro.jar and concurrent.jar which
are in the
root of the webmacro folder /release.
•
•
•
•
•
•
•
•
•
b) The preferred method to build your example app is to use the ant
build.xml file.
Edit the build.xml file in the examples directory. Set your web home variable
in the build file and run the task "web" which will extract the files
from the release and examples directory. It will compile and build a
ready-to-go web application running under Tomcat.
Config continued
• For example, if your TOMCAT_HOME is \tomcat then,
(a) or (b) should result in a web
• application in \tomcat\webapps\wm. The directory tree
will look like this:
• HTML, XML and text:
•
\tomcat\webapps\wm\index.html
•
\tomcat\webapps\wm\README
•
\tomcat\webapps\wm\build.xml
• WebMacro configuration fil
•
\tomcat\webapps\wm\WebMacro.properties
Config continued
•
•
Sample batch file for compiling sources:
\tomcat\webapps\wm\build.bat
•
•
•
•
•
•
•
•
•
•
•
•
•
Templates:
\tomcat\webapps\wm\allguest.wm
\tomcat\webapps\wm\callgraph.wm
\tomcat\webapps\wm\error.wm
\tomcat\webapps\wm\form.wm
\tomcat\webapps\wm\helloWorld.wm
\tomcat\webapps\wm\noservlet.wm
\tomcat\webapps\wm\profile.wm
\tomcat\webapps\wm\sandbox.wm
\tomcat\webapps\wm\verify.wm
\tomcat\webapps\wm\WEB-INF\classes\standalone.wm
advanced templates
\tomcat\webapps\wm\advanced\index.html and advanced\*.tml
Config continued
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Java sources:
\tomcat\webapps\wm\GuestBook.java
\tomcat\webapps\wm\HelloWorld.java
\tomcat\webapps\wm\NoServlet.java
\tomcat\webapps\wm\Profile.java
\tomcat\webapps\wm\SandBox.java
\tomcat\webapps\wm\Standalone.java
Class files:
\tomcat\webapps\wm\WEB-INF\classes\GuestBook$GuestEntry.class
\tomcat\webapps\wm\WEB-INF\classes\GuestBook.class
\tomcat\webapps\wm\WEB-INF\classes\HelloWorld.class
\tomcat\webapps\wm\WEB-INF\classes\NoServlet.class
\tomcat\webapps\wm\WEB-INF\classes\Profile.class
\tomcat\webapps\wm\WEB-INF\classes\SandBox.class
\tomcat\webapps\wm\WEB-INF\classes\Standalone.class
WebMacro jar:
\tomcat\webapps\wm\WEB-INF\lib\webmacro.jar
Web App Configuration
\tomcat\webapps\wm\WEB-INF\web.xml
The web.xml file will activate the Tomcat invoker so you can run the servlet examples.
install
• I used method (a) above and complete
install only took 15 minutes or so… the
java class files are already there, you just
need to move the jar files into the lib
directory.
• I did uncomment the template path in the
properties file and move all the templates
from the webapp root to a templates
directory (under WEB-INF)
Web.xml if you use the servlet
invoker
<web-app>
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
</web-app>
Hand installation
• in the properties file you may need to
configure the TemplatePath which
specifies the directory (or directories)
where your templates are stored.
• In fact, current webmacro version doesn’t
typically need this step, but template path
can be specified in the
webmacro.properties file in your servlet
context.
From download docs:
Set Up Guidelines
Updated For Release 2.0
• WebMacro is a free Java development package that allows you to
keep HTML and presentational issues out of your Java servlet code-while providing web designers with a simple template language
capable of displaying any Java object. In stand alone mode, it is a
powerful language generation platform for java.
• Some basic guidelines for set-up:
• for web apps, webmacro.jar contains all the core classes, and needs
to be in your classpath or your WAR distribution. Also,
concurrent.jar, provided in the distribution, needs to be in your
classpath as well.
• webmacro.defaults contains all the runtime default properties. DO
NOT MODIFY this file. Instead override this file by placing a file
called WebMacro.properties in your classpath and making changes
or replacements here. For secure 2.2+ Web Apps, place
WebMacro.properties under your WEB-INF/classes directory where
it will be automatically found in this classpath.
From download docs:
Set Up Guidelines
Updated For Release 2.0
• We recommend you place the root directory for your templates in
your classpath or your application root or for secured WEB
applictions in a jar file in the directory WEB-INF/lib/. In this manner,
the WebMacro resource provider will find them. For example, if you
place your templates is WEB-INF/classes, they will be found
because this path is automatically a part of the classpath for web
applications.
• API documentation is provided with the release and is your principal
source of coding guidelines along with the WebMacro wiki site.
• Examples contains a few example WebMacro programs and
templates for you to look at to figure out how things work. Complete
driving instructions are found at the interactive WebMacro site.
From download docs: How To Use It
• Note: See also Configuring-Examples in this directory.
• This applies to the HelloWorld, Standalone, and GuestBook
examples. These classes are servlets. Compile them and install
them in your servlet directory. Note that there are multiple .class files
for GuestBook, so be sure to copy all of them.
• Then follow the instructions below to configure your classpath. If the
templates are in your classpath, you will not need to create and then
specify a path to your template file.
• You need to have the a servlet runner installed and working, or an
equivalent servlet interface, and it has to be in your CLASSPATH.
• As of this release, we recommend using Java 1.4 or 1.5 runtime.
• Again, webmacro.jar and concurrent.jar must be in your classpath.
• Here is an example CLASSPATH:
CLASSPATH=$JAVA_HOME/lib/classes.zip:$HOME/webmacro/web
macro.jar:$HOME/WebMacro/examples:$JSDK_HOME You have
unpacked WebMacro in your home directory in this example.
$JSDK_HOME contains the "javax" directory in which you have your
JSDK base classes, and JAVA_HOME/lib/classes.zip contains the
J2SE standard library.
From the docs:
• Using the examples
• Follow the steps above. Then read the comments at the head of
each examples .java file for detailed instructions. Note that the
examples are not pre-compiled, you must compile them.
• HelloWorld and GuestBook use the WMServlet approach, so put all
their .class files in your servlet directory, normally, WEB-INF/classes.
• How to Compile WebMacro
• WebMacro ships with a webmacro.jar file compiled for JDK 1.2-1.5.
To recompile WM, you will need to go to the CVS archive where you
can find the ant build script and all the supporting libraries
referenced during compilation. You must "check out" the sources
and supporting files to compile and test WM.
Overview of the WebMacro System
• WebMacro provides, among other benefits, a cleaner
approach to web page generation than using JSP/ASP.
Philosophically:
• We think it is wrong to use markup for a scripting
language
• We think it is wrong to embed programs on a web page
• We think it is wrong for web scripts to look like hard
programming
• We feel that an API like WM should make it easy to do
the things you need to do when designing and deploying
applications.
• We believe that programming and graphical page
design are separate tasks
• JSP/ASP are hard to do for web page designers.
WebMacro is not. So we have designed a language that
is simple to learn, but which fits with our biases above.
WebMacro presents two separate interfaces:
•
•
•
•
•
A template language for web page designers to use, into which they can
substitute values from a web program
A library and framework for web based programming, for use by technical
developers, which is independent of any layout or other graphical concerns
You might be both a graphics designer AND a programmer. Many people
are. However I think you will agree that these activies use different sides of
your brain--or at least very different kinds of thinking--and it is painful to try
and do both at the same time. Alternately you might be a programmer
working with a web designer: By providing the web designer with a list of
variables which they can substitute into a page, you keep the designer at
some distance from your sensitive program codes. At the same time, the
designer is free to take those variables and lay them out any which way
they please.
This separation of program code and content is the fundamental idea
behind the WebMacro system.
Lastly, WM is a powerful language for code generation, mail merging and
rule development. A WebMacro template can contain simple business logic.
When a template is evaluated, the simple logic can interact with more
complex java and state processing. This makes for a formidable framework
for language generation. WebMacro is a language platform.
How it works
• WebMacro relies heavily on introspection to glue
your template to your back-end.
• On your back end you stick ordinary Java
objects into your Context.
• WebMacro will then introspect these objects and
make them available as properties in the
template.
• Introspection is fairly expensive so WebMacro
avoids doing this at execution time.
• The first time a class is introspected WebMacro
caches the knowledge it gains about the class
for efficient use in the future.
• Templates are also compiled into a form suitable
for rapid-execution on first use. (Note that you
have to turn on the Template caching in your
WebMacro.properties file to see this behavior.)
How it works
• The overall design of WebMacro is that the state for
each request is contained in this Context object: you
need to instantiate a new Context for every request (you
can create a prototype Context and then clone it for
efficiency--this is automatically done for you most of the
time.)
• Since the state for each request is entirely contained
within the Context, templates can be shared between
multiple requests. Since templates have no state, they
don't need to be synchronized. Since Contexts are
accessed by only one thread ("thread per request") they
don't need to be synchronized either. Thus you get very
good performance out of WebMacro since most of the
code can avoid the overhead of synchronization locks.
How it works
• Finally, WebMacro is a framework. Most of its behavior is
loaded dynamically based on the configuration file,
WebMacro.defaults and if present,
WebMacro.properties. The effect of this is that you can
radically alter the behavior of WebMacro by replacing the
classes named in WebMacro.properties with your own.
There are a large number of "plug points" in the design
to allow an advanced user to customize WebMacro
extensively.
• For an ordinary user, though, it's good enough to rely on
the default configuration. All you have to do is create
contexts and load templates using the provided
WebMacro interfaces. See the examples provided in the
examples directory for more information.
INSTALLING THE EXAMPLES (1)
• There are some examples using HttpServlet
instead of a webmacro servlet.
• There are also some applications (not applets or
servlets) showing that webmacro is not limited to
internet applications.
• The servlet examples can be moved into their
own webcontext (wm). The web.xml file,
webapps directory, WEB-INF and classes
directories are already in the right places with
the correct contents.
• I just used file copy. You can rebuild everything
(using the ant tool).
• The java files are there, too.
• The wm files sit in the root directory of the
context. (so no template path is needed to find
them).
INSTALLING THE EXAMPLES (2)
•
•
•
With the advanced examples, no effort has been made
to reproduce finished applications. Rather, the specimens in the
advanced directory represent production, unit test java or webmacro
templates which illustrate one or more areas of WebMacro usage.
•
•
The servlet examples expect a servlet container
such as Tomcat and Resin, two popular Java servlet containers. Other
examples, eg, Standalone.java, do not require a servlet container to use.
Care has been made to remain backward compatible with all servlet specs
from 2.2 thru 2.4.
Compliant servlet containers should work very similarly.
The sources were compiled using Sun's JDK1.4 and JDK1.5. Both JDKs are
supported under Release 2 of WebMacro.
Unix/Linux configuration should be virtually identical (except for the slashes
and drive letters in the paths). All paths given such as
release/examples/ are relative to "release" which will be a
specific version, eg, "webmacro-2.0".
•
•
•
•
•
•
•
•
•
TOMCAT CONFIGURATION ( tested v5.5.9)
•
There are two ways to get started:
•
•
•
•
a) Copy the files from release/examples/* to a webapps directory named wm/. This
will create a working web application. You will want to manually copy jar files
to the WEB-INF/lib folder such as webmacro.jar and concurrent.jar which are in the
root of the webmacro folder /release.
•
•
•
•
•
•
•
•
b) The preferred method to build your example app is to use the ant build.xml file.
Edit the build.xml file in the examples directory. Set your web home variable
in the build file and run the task "web" which will extract the files
from the release and examples directory. It will compile and build a
ready-to-go web application running under Tomcat.
•
•
•
•
HTML, XML and text:
\tomcat\webapps\wm\index.html
\tomcat\webapps\wm\README
\tomcat\webapps\wm\build.xml
•
•
WebMacro configuration fil
\tomcat\webapps\wm\WebMacro.properties
•
•
Sample batch file for compiling sources:
\tomcat\webapps\wm\build.bat
For example, if your TOMCAT_HOME is \tomcat then, (a) or (b) should result in a web
application in \tomcat\webapps\wm. The directory tree will look like this:
tomcat summary
•
•
•
•
•
•
•
•
•
•
•
•
•
Templates:
\tomcat\webapps\wm\allguest.wm
\tomcat\webapps\wm\callgraph.wm
\tomcat\webapps\wm\error.wm
\tomcat\webapps\wm\form.wm
\tomcat\webapps\wm\helloWorld.wm
\tomcat\webapps\wm\noservlet.wm
\tomcat\webapps\wm\profile.wm
\tomcat\webapps\wm\sandbox.wm
\tomcat\webapps\wm\verify.wm
\tomcat\webapps\wm\WEB-INF\classes\standalone.wm
advanced templates
\tomcat\webapps\wm\advanced\index.html and advanced\*.tml
•
•
•
•
•
•
•
•
Java sources:
\tomcat\webapps\wm\GuestBook.java
\tomcat\webapps\wm\HelloWorld.java
\tomcat\webapps\wm\NoServlet.java
\tomcat\webapps\wm\Profile.java
\tomcat\webapps\wm\SandBox.java
\tomcat\webapps\wm\Standalone.java
tomcat summary(2)
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Class files:
\tomcat\webapps\wm\WEB-INF\classes\GuestBook$GuestEntry.class
\tomcat\webapps\wm\WEB-INF\classes\GuestBook.class
\tomcat\webapps\wm\WEB-INF\classes\HelloWorld.class
\tomcat\webapps\wm\WEB-INF\classes\NoServlet.class
\tomcat\webapps\wm\WEB-INF\classes\Profile.class
\tomcat\webapps\wm\WEB-INF\classes\SandBox.class
\tomcat\webapps\wm\WEB-INF\classes\Standalone.class
WebMacro jar:
\tomcat\webapps\wm\WEB-INF\lib\webmacro.jar
Web App Configuration
\tomcat\webapps\wm\WEB-INF\web.xml
The web.xml file will activate the Tomcat invoker so you can run the servlet examples.
NOTE ON TEMPLATE PATHS*
Notice that all the templates are located in the applications root directory
except for standalone.wm. The "Standalone" example instantiates WM directly
and does not extend WMServlet. Because of this its broker does not have
access to the ServletContext. The other examples all extend WMServlet and
thus are able to get their resources (templates) through the ServletContext.
This feature is only available with JSDK2.2+ compatable servlet containers.
By putting the template in the classes directory, the Standalone servlet is
able to locate it through the classpath.
The alternative would have been to add a TemplatePath to the
webmacro.properties file. For example, you could put all of the templates
in \tomcat\webapps\wm\WEB-INF\templates and add:
TemplatePath: \tomcat\webapps\wm\WEB-INF\templates
to the WebMacro.properties file. This technique should work with all
servlet containers. The major drawback is that it requires a manual
configuration step (since we can't know what directory you will use) which
is a frequent cause of configuration problems. The other methods will work
out of the box, even without a WebMacro.properties file.
invoking servlets
• web-macro enabled servlets can be invoked like any
other. For example,
http://localhost:8080//servlet/WMHello
• if they are located under the webmacro context
(webmacro/templates) then the URL is
http://localhost:8080/webmacro/servlet/WMHello
Examples (readme.txt)
• These trivial examples are intended to help you get started with
• WebMacro. We suggest you try the HelloWorld example first, as it
• is the easiest to get going.
• [NOTE: For information on getting the examples configured on your
system see
• the document CONFIGURING-EXAMPLES in the webroot directory
of this
• distribution or the Wiki page at
http://www.webmacro.org/ConfiguringExamples]
• In each case you will find comments inside the .java file explaining
• what the example is, and how to get it working.
• Previous versions of WebMacro *required* you to customize the
WebMacro.properties
• file, espically the "TemplatePath" value. This is no longer required!
In fact,
• in most cases you don't even need a WebMacro.properties file!
Readme.txt continued
•
•
•
•
•
•
Included in the webmacro.jar file is a file named "WebMacro.defaults". This
file contains all the default configuration settings for WebMacro. Should
you need to change a key/value, DO NOT change it in the WebMacro.defaults.
Create a new file, "WebMacro.properties", and put in it *only* the keys/values
you wish to change. WebMacro first loads it's .defaults, then if it exists
loads WebMacro.properties overriding any values set by .defaults.
•
•
Also, you no longer need to specify a TemplatePath. WebMacro, depending on your
execution environment, will automagically find your templates:
•
•
•
1) WM in standalone mode (ie, not in a servlet):
If using the "new WM();" constructor, WebMacro will search for templates in
your system CLASSPATH
•
•
2) WM in a Servlet 2.0 environment (ie, Apache/JServ):
WebMacro will search for templates in your servlet container CLASSPATH
•
•
•
•
3) WM in a Servlet >2.0 environment (ie, Turbine or Resin):
WebMacro will search for templates in your "application directory". This
means different things for different servlet runners, but will include either
your "htdocs" directory or your WEB-INF/ directory/.war file.
readme continued
Below is an overview of the examples included with this release:
HelloWorld
---------A servlet. Demonstrates the basic workings of WebMacro, with lots
of comments explainig each step. Try installing this one first.
GuestBook
--------A servlet. Intended to give you an application with several
different templates, so you can experiment with customizing it.
Also shows WebMacro using and introspecting some ordinary objects.
Profile
------A servlet that illustrates how to use the #profile directive to time
various operations in a WebMacro application.
To use this example, you must enable the #profile directive. See the
comments in profile.wm or Profile.java for more information.
readme continued
Standalone
---------An advanced HelloWorld servlet that does *not* subclass WMServlet. This
example, although a servlet, manages it's own WebMacro instance internally.
It also demonstrates how to create FastWriters, Contexts, and how to write
Templates. If you're trying to fit WebMacro into an existing servlet
application, this example will be of the most benefit for you.
Sandbox
------A servlet. This is basically another version of the HelloWorld servlet.
It is provided as a place where you can start playing with WebMacro by
just editing the template -- sandbox.wm -- and the servlet Sandbox.java.
Have fun exploring.
NoServlet
--------A standalone command-line program which demonstrates how to create
a WebMacro instance and a Context along with getting and writing
a template. If you plan on using WebMacro outside of a servlet
environment, look here first!
wm/index page
HelloWorld wm servlet
HelloWorld wm servlet slide1
// import the WebMacro core interfaces
import org.webmacro.*;
// import the WebMacro servlet classes
import org.webmacro.servlet.*;
public class HelloWorld extends WMServlet
{
/**
* WebMacro creates a WebContext and passes it to your servlet.
* The WebContext contains all the information you'll need to
* handle the request. It is also the only object you share
* with the template. If you add objects to the WebContext via
* its put(key,value)method,they become available in the
* template as variables named after the key.
*/
public Template handle(WebContext context) throws HandlerException
{
// Put whatever data you like into the context. In
// this example we just put in a simple string
context.put("Hello", "Hello, brave new world!");
// Select a template. You could choose the template based
// on any criteria you like: user preference, current
// action, different templates for different results, etc.
// We need to acquire a template somehow
Template view;
hello slide 2
try {
// The following line asks WebMacro's resource broker to
// find the "helloWorld.wm" template, cache it, and return a
// parsed copy to us.
view = getTemplate("helloWorld.wm");
} catch (ResourceException e) {
// If this happens you have not set WebMacro up correctly:
// either WebMacro isn't up and running well enough to be able
// to locate any template, or else we asked for a template which
// doesn't exist. However, the HelloWorld.wm example should exist
// if you have everything set up properly!
throw new HandlerException(
"HelloWorld loaded and executed OK, but was unable to load \n"
+ "a template. There are a couple of things that could be wrong \n"
+ "here. First, you may have put webmacro.properties somewhere \n"
+ "outside your servlet classpath. Try putting it in the same \n"
+ "place as you put webmacro.jar. Second, you may have set the \n"
+ "TemplateRoot directory incorectly. The file helloWorld.wm \n"
+ "must be in one of the directories listed in that option in \n"
+ "the webmacro.properties file. You should check the server \n"
+ "logs or output (or WebMacro's log if it's set and being used \n"
+ "for helpful messages which may indicate what the problem is. \n"
+ "Since your servlet runner may have d fewifferent classpath \n"
+ "settings, check that webmacro.properties is in the same \n"
+ "classpath that was used to load webmacro.jar. \n"
+ "\n", e);
}
// Now that we have done all our processing, it's time to produce
// some output. We return the template we have created. WebMacro
// will automatically execute it for us. If you don't want this
// to happen, you can return "null" instead and WebMacro will
// do nothing-return view; }}
GuestBook
GuestBook (submit)
see Guests
CheckConfig servlet
Standalone slide 1 (note parameter)
passes itself form variables as parameters
passes itself form variables as parameters
Sandbox servlet
Sandbox.java
import org.webmacro.*;
import org.webmacro.servlet.*;
/**
* SandBox - where to play
*/
public class SandBox extends WMServlet
{
public Template handle(WebContext context) throws HandlerException
{
// Put whatever data you like into the context. In
// this example we just put in a simple string
context.put("Hello", "Hello, brave new world!");
// Select a template. You could choose the template based
// on any criteria you like: user preference, current
// action, different templates for different results, etc.
// We need to acquire a template somehow
Template view;
try {
// The following line asks WebMacro's resource broker to
// find the "helloWorld.wm" template, cache it, and return a
// parsed copy to us.
view = getTemplate("sandbox.wm");
} catch (ResourceException e) {
// If this happens you have not set WebMacro up correctly:
// either WebMacro isn't up and running well enough to be able
// to locate any template, or else we asked for a template which
// doesn't exist. However, the HelloWorld.wm example should exist
// if you have everything set up properly!
throw new HandlerException(
"SandBox was unable to load \n"
+ "a template. \n\n"
+ "Here is the actual exception that was raised:\n" + e);
}
return view; }}
Sandbox.wm
• <html>
•
<body>
•
<h1>Sand Box</h1>
•
</body>
• </html>
Creating your own webmacro
servlets and wm from scratch
Finding org.webmacro.*
• I had to unzip the webmacro.jar file to get the servlet to
compile. I unzipped it to bin and it puts stuff in
org/webmacro/etc
• The web.xml file they have uses invoker to find your
servlet so no further adjustment is needed to this file for
deployment
• Of course, you need to drop class file and wm file where
they go. (class as usual, wm in the webapp root)
• As mentioned in wm docs, no need to set Template path
MyHelloWorld
web.xml uses servlet invoker and really saves work!
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-Copyright 2004 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
I cut out some of the license info
-->
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
</web-app>
myhelloworld.wm
<html><head><title>My Hello, World Wm Servlet Ex</title></head>
## You have to set the content type. You could do this from
## the servlet instead--but this way your page designer can
## change it if XML was wanted. What the line below does is
## use WebMacro's introspection to find and use the method:
##
## WebContext.getResponse().setContentType("text/html")
#set $Response.ContentType = "text/html"
## Now the rest of your HTML, including a few example WebMacro
## statements, just for fun. Note the use of the $Hello variable
## which is defined in the HelloWorld servlet.
<h1>$Hello</h1>
<ul>
#set $go = "<font color=red size=+1><b>$Goodbye</b><p>$Other</p></font>"
#foreach $count in [ "CS116", "CS201", "CS203", "CS345", "$go" ] {
<li>$count
}
</ul>
Thanks for viewing my webmacro example!
</body></html>
MyHelloWorld.java
import org.webmacro.*;
// import the WebMacro servlet classes
import org.webmacro.servlet.*;
public class MyHelloWorld extends WMServlet
{
/**
* WebMacro creates a WebContext and passes it to your servlet.
* The WebContext contains all the information you'll need to
* handle the request. It is also the only object you share
* with the template. If you add objects to the WebContext via
* its put(key,value)method,they become available in the
* template as variables named after the key.
*/
public Template handle(WebContext context) throws HandlerException
{// Put whatever data you like into the context. In
// this example we just put in a simple string
context.put("Hello", "Isn't Higgins Great???!");
context.put("Goodbye", "whatever message goes here");
context.put("Other", "more message might go here");
// Select a template. You could choose the template based
// on any criteria you like: user preference, current
// action, different templates for different results, etc.
// We need to acquire a template somehow
Template view;
try {
// The following line asks WebMacro's resource broker to
// find the "helloWorld.wm" template, cache it, and return a
// parsed copy to us.
view = getTemplate("myhelloWorld.wm");
} catch (ResourceException e) {
more of it
// If this happens you have not set WebMacro up correctly:
// either WebMacro isn't up and running well enough to be able
// to locate any template, or else we asked for a template which
// doesn't exist. However, the HelloWorld.wm example should exist
// if you have everything set up properly!
throw new HandlerException(
"HelloWorld loaded and executed OK, but was unable to load \n"
+ "a template. There are a couple of things that could be wrong \n"
+ "here. First, you may have put webmacro.properties somewhere \n"
+ "outside your servlet classpath. Try putting it in the same \n"
+ "place as you put webmacro.jar. Second, you may have set the \n"
+ "TemplateRoot directory incorectly. The file helloWorld.wm \n"
+ "must be in one of the directories listed in that option in \n"
+ "the webmacro.properties file. You should check the server \n"
+ "logs or output (or WebMacro's log if it's set and being used \n"
+ "for helpful messages which may indicate what the problem is. \n"
+ "Since your servlet runner may have d fewifferent classpath \n"
+ "settings, check that webmacro.properties is in the same \n"
+ "classpath that was used to load webmacro.jar. \n"
+ "\n", e);
}
// Now that we have done all our processing, it's time to produce
// some output. We return the template we have created. WebMacro
// will automatically execute it for us. If you don't want this
// to happen, you can return "null" instead and WebMacro will
// do nothing-return view; }
}
MacroView servlet (from our text)
MacroView
import org.webmacro.*;
import org.webmacro.servlet.*;
import org.webmacro.engine.*;
import org.webmacro.broker.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Extending com.oreilly.servlet.CacheHttpServlet can improve response time
public class MacroView extends HttpServlet {
WebMacro wm; // WebMacro main hook
//got rid of FastWriter
public void init(ServletConfig sc) throws ServletException {//had to change this to call super.init(sc)
super.init(sc);
try {
if (wm == null) {
wm = new WM(this);
}
} catch (InitException e) {
throw new ServletException("Could not initialize WebMacro: " + e);//changed this line
} }
MacroView
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// The template name comes as extra path info
// /servlet/MacroView/templ.wm
// or as servlet path via a *.wm rule
// /templ.wm
String template = req.getPathInfo();
if (template == null) {
template = req.getServletPath();
template = template.substring(1); // cut off leading "/"
}
// If template is still null, we have a problem
if (template == null) {
throw new ServletException(
"No template specified as extra path info or servlet path"); }
try {
Template tmpl = wm.getTemplate(template);
WebContext context = wm.getWebContext(req, res);
tmpl.write(res.getOutputStream(),res.getCharacterEncoding(), context);
}
catch (WebMacroException e) {
throw new ServletException("wm exception"+e);//changed this
} }
public void destroy() { wm = null;}}//changed this line,too
Macroview displays (runs) a wm
macro
I adjusted text code which went looking in
the classes directory for wm file
String template = req.getPathInfo();
if (template == null) {
template = req.getServletPath();
}
// template = template.substring(1);
//absolute path info:
template="c:/jakart~1.10/webapps/wm/WEBINF/templates"+template;
A note…
• I did most of the examples here a year ago
on another machine and redid most this
year. Not much new except a few notes:
• I couldn’t text examples with fastwriter or
logs classes to compile... I worked around.
ToolServlet in wm…
• remember you’ll need jdom in the webinf/ lib and the Tool.class
compiled and in the classes directory.
• You’ll need an init parameter (toolsfile)
• Hint:
<servlet>
<servlet-name>XXXXX</servlet-name>
<servlet-class>
XXXXX
</servlet-class>
<init-param>
<param-name>initialguy </param-name>
<param-value>12345</param-value>
</init-param>
</servlet>
• You’ll need some image files to use for the header if you want that to
appear…Could be these are somewhere in the text examples.
ToolServlet in wm…
about WebMacro
• Webmacro parses templates and stores
them in memory afterwards for fast
processing. It reparses after file changes,
checking the date stamp to determine if
necessary.
• The expiration time is set in webmacros
properties file (defaults to 0 so it reparses
on every request).
about WebMacro
• Webmacro will try to generate a page as
best it can, pasting in error message if
some variables or properties don’t exist or
are null.
• servlets can route to .wm files for error
display.
Toolview Servlet
JDOM
• The tool class used JDOM. I had DOM
but not JDOM. This is a 3mg download. I
unzipped the jdom.jar.
• It goes in classes/org/jdom
Tool.java
import java.io.*;
import java.sql.*;
import java.util.*;
import org.jdom.*;
import org.jdom.input.*;
public class Tool {
// Data about this tool record
public int id;
public String name;
public String homeURL;
public String comments;
public String stateFlag;
public Timestamp createdTime;
public Timestamp modifiedTime;
// Tea can only access bean properties, so accessor methods are required
public int getId() { return id; }
public String getName() { return name; }
public String getHomeURL() { return homeURL; }
public String getComments() { return comments; }
public String getStateFlag() { return stateFlag; }
public Timestamp getCreatedTime() { return createdTime; }
public Timestamp getModifiedTime() { return modifiedTime; }
Tool.java
public int getCreatedAgeInDays() {
return (int) ((System.currentTimeMillis() - createdTime.getTime()) /
(24 * 60 * 60 * 1000)); // millis in a day
}
public int getModifiedAgeInDays() {
return (int) ((System.currentTimeMillis() - modifiedTime.getTime()) /
(24 * 60 * 60 * 1000)); // millis in a day
}
// Ideally we'd use methods like these, but Tea only allows property
// access on an object. These won't be visible.
public boolean isNewWithin(int days) {
return getCreatedAgeInDays() < days;
}
public boolean isUpdatedWithin(int days) {
return getModifiedAgeInDays() < days;
}
Tool.java
public static Tool[] loadTools(String toolsFile) throws Exception {
// Read the tool data from an XML file containing <tool> elements
// Use the JDOM API to keep things simple (http://jdom.org)
List toolObjects = new LinkedList();
SAXBuilder builder = new SAXBuilder();
Document document = builder.build(new File(toolsFile));
Element root = document.getRootElement();
List toolElements = root.getChildren("tool");
Iterator i = toolElements.iterator();
while (i.hasNext()) {
Element tool = (Element) i.next();
Tool t = new Tool();
t.id = tool.getAttribute("id").getIntValue();
t.name = tool.getChild("name").getTextTrim();
t.homeURL = tool.getChild("homeURL").getTextTrim();
t.comments = tool.getChild("comments").getTextTrim();
t.stateFlag = tool.getChild("stateFlag").getTextTrim();
t.createdTime = Timestamp.valueOf(
tool.getChild("createdTime").getTextTrim());
t.modifiedTime = Timestamp.valueOf(
tool.getChild("modifiedTime").getTextTrim());
toolObjects.add(t);
}
return (Tool[]) toolObjects.toArray(new Tool[0]);
}
}
ToolServlet
import org.webmacro.*;
import org.webmacro.servlet.*;
import org.webmacro.util.*;
import java.io.*;
import java.sql.*;
import java.util.*;
import javax.servlet.*;
public class ToolServlet extends WMServlet {
private Log log;//this class didn’t seem to work
private Tool[] tools;
public void init(ServletConfig sc) throws ServletException {
try{
super.init(sc);//added this
}catch (ServletException e){}
}
ToolServlet
public void start() throws ServletException {
// Load the tool data in our init for simplicity
// String toolsFile = getInitParameter("toolsFile"); // from web.xml
// if (toolsFile == null) {
// throw new ServletException(
//
"A tools data file must be specified as the toolsFile init parameter");
// }
//log = new Log(getServletName(), "Tool example debugging log");
// log.debug("Loading tools from tools.xml");
try {
tools = Tool.loadTools("tools.xml");//hard coded this instead of taking a parameter
if (tools.length == 0) {
// log.warning("No tools found " );//no log file in use
}
else {
// log.info(tools.length + " tools found ");
} }
catch (Exception e) {
// log.info(""+e);
throw new ServletException("wm exception"+e);
}
}
}
ToolServlet
// Creating a context provides functions accesible from the templates.
public Template handle(WebContext context) throws HandlerException {
// You often pass on the request, response, and application even if
// not all the objects are used, since they may be used later
try {
Template view = getTemplate("toolview.wm");
String state = context.getRequest().getParameter("state");
if (state == null) {
state = (String)view.getParam("defaultState");
}
if (state == null) {
context.put("tools", getTools());
}
else {
context.put("tools", getTools(state));
}
return view; }
catch (WebMacroException e) {
// log.info(""+e);
throw new HandlerException(e.getMessage()); }
catch (IOException e) {
// log.info(""+e);
throw new HandlerException(e.getMessage()); } }
public Tool[] getTools() { return tools; }
public Tool[] getTools(String state) {
List list = new LinkedList();
for (int i = 0; i < tools.length; i++) {
if (tools[i].getStateFlag().equalsIgnoreCase(state)) {
list.add(tools[i]);
} }
return (Tool[]) list.toArray(new Tool[0]); }
just a little of tools.xml – needs to
be in tomcat/bin
<?xml version="1.0"?>
<tools>
<tool id="1">
<name>JavaServer Pages</name>
<homeURL>http://java.sun.com/products/jsp</homeURL>
<comments>
JavaServer Pages (JSP) is a technology created by Sun Microsystems
and closely tied to servlets. As with servlets, Sun releases a JSP
specification, and third party vendors compete on their implementation
of that standard. Being released by Sun puts JSPs in a very privileged
position, and had JSP solved a sufficient number of user problems it
would probably have won the market before there were any other viable
entries. As is, a surprising number of users are disenchanted with JSP
and alternatives are gaining popularity.
</comments>
<stateFlag>LIVE</stateFlag>
<createdTime>1998-03-17 00:00:00.000</createdTime>
<modifiedTime>1999-12-16 00:00:00.000</modifiedTime>
</tool>
Blog site
• Guestbook example provides some good
ideas for interface features of a blog site.
• Of course, a database would be needed.
• The GuestbookEntry needs to be moved
out of the Guestbook class so other
servlets can use it.
Blogsite…entry
public final class BlogEntry
{
final private String name;
final private String email;
final private String topic;
final private String comment;
public BlogEntry(String inName, String inEmail, String inTopic, String inComment)
{
name = inName;
email = inEmail;
comment = inComment;
topic=inTopic;
}
final public String getName()
{
return name;
}
final public String getEmail()
{
return email;
}
final public String getTopic()
{
return topic;
}
final public String getComment()
{
return comment;
}
}
BlogSite built by modifying
Guestbook
import java.util.*;
import org.webmacro.servlet.*;
import org.webmacro.*;
import org.webmacro.util.*;
public class BlogSite extends WMServlet
{
ArrayList book = new ArrayList();
String name;
String email;
String topic;
String comment;
BlogEntry myBlogEntry;
final static private boolean debug = false;
BlogSite
public Template handle(WebContext context)
throws HandlerException
{
context.getResponse().setContentType("text/html");
Object output = new Object();
String templateName;
// get the form variables
output = (String) context.getForm("loadFile");
name = (String) context.getForm("name");
email = (String) context.getForm("email");
topic=(String)context.getForm("topic");
comment = (String) context.getForm("comment");
if (output == null) {
output = "blogform.wm";
templateName = "blogform.wm";//formerly form.wm
}
if (name == null) {
name = "<!-- form variable 'name' not defined -->";
}
if (email == null) {
email = "<!-- form variable 'email' not defined -->";
}
if (topic == null) {
topic = "<!-- form variable 'topic' not defined -->";
}
if (comment == null) {
comment = "<!-- form variable 'comment' not defined -->";
}
Blogsite
// verifying for submissions
if (output.equals("verify")) {
myBlogEntry = new BlogEntry(name, email, topic, comment);
book.add(myBlogEntry);
context.put("blogrecord", book);
templateName = "verifyblog.wm";//formerly verify.wm
// for guest book view
} else if (output.equals("displayall")) {//formerly allguest
context.put("blogrecord",book);
templateName = "displayall.wm";//formerly allguest.wm
// default
} else {
templateName = "blogform.wm";//formerly form
}
// return the appropriate template
try {
Template t = getTemplate(templateName);
return t;
} catch (Exception e) {
throw new HandlerException("Could not load template: "
+ templateName
+ ".<br><br>The system reported the following error:<br>" + e.getMessage());
}
}
}
Wm files
• verify.wm, allguest.wm, and form.wm from
the guest book can be converted into wm
files that work ok for the revised (blog)
class.
Template output
• t.write(resp.getOutputStream(),
resp.getCharacterEncoding(), c);
•
} catch (org.webmacro.ResourceException e) {
•
resp.getWriter().write("ERROR! Could not
locate template standalone.wm, check that your template
path is set properly in WebMacro.properties");
•
} catch (org.webmacro.ContextException e) {
•
resp.getWriter().write("ERROR! Could not
locate required data in the Context.");
•
}
•
} catch (java.io.IOException e) {
•
// what else can we do?