Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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?