1
2
3
4
5
6
7 package org.webmacro.servlet;
8
9 import org.webmacro.Context;
10 import org.webmacro.PropertyException;
11 import org.webmacro.Template;
12 import org.webmacro.ContextTool;
13 import org.webmacro.engine.StringTemplate;
14
15 import java.util.ArrayList;
16
17
18
19 /*** This is an experimental context tool that allows templates
20 * to be used as macros. The tool places a
21 * MacroTemplateFactory instance into the context that can
22 * be referenced as $Template in WMScript. The factory has
23 * two methods, each of which returns a MacroTemplate object,
24 * created either from a string or a file.
25 *
26 * @author Keats Kirsch
27 * @version 0.2
28 */
29 public class TemplateTool extends ContextTool
30 {
31
32 private Context _context = null;
33 /***
34 * flag set when destroy is first called, to prevent subsequent calls from
35 * invoking the destroy() method on the factory object.
36 */
37 private boolean _destroyed = false;
38
39 /*** Creates new TemplateTool */
40 public TemplateTool ()
41 {
42 }
43
44 /*** Create a factory object that can be accessed from WMScript as
45 * $Template for creating MacroTemplate objects.
46 * @param c The context of the current request.
47 * @throws PropertyException From the ContextTool interface
48 * @return a new MacroTemplateFactory for each request.
49 */
50 public Object init (Context c) throws PropertyException
51 {
52 _context = c;
53 return new MacroTemplateFactory(c);
54 }
55
56 /*** A factory class for creating MacroTemplate objects.
57 */
58 public class MacroTemplateFactory
59 {
60
61 private Context _context;
62 private ArrayList _macros = new ArrayList(10);
63
64 /*** Constructor
65 * @param ctx the context for the current request
66 */
67 public MacroTemplateFactory (Context ctx)
68 {
69 _context = ctx;
70 }
71
72 /*** Creates a MacroTemplate from a string with a new context.
73 * @param s the template string
74 * @return the new MacroTemplate
75 */
76 public MacroTemplate fromString (String s)
77 {
78 MacroTemplate mt = new MacroTemplate(_context, s);
79 _macros.add(mt);
80 return mt;
81 }
82
83 /*** Creates a MacroTemplate from a file reference with a
84 * new context.
85 * @param fileRef a reference to the template file
86 * @throws org.webmacro.ResourceException if the file cannot be found or parsed
87 * @return a new MacroTemplate
88 */
89 public MacroTemplate fromFile (String fileRef)
90 throws org.webmacro.ResourceException
91 {
92 Template t = (Template) _context.getBroker()
93 .getProvider("template").get(fileRef);
94 MacroTemplate mt = new MacroTemplate(_context, t);
95 _macros.add(mt);
96 return mt;
97 }
98
99 }
100
101 /*** Encapsulates a template and a context, allowing a template
102 * to be used like a function or "macro".
103 */
104 public class MacroTemplate
105 {
106
107 private Template _template;
108 private Context _context, _origContext;
109
110 /*** Constructor
111 * @param c the current request context
112 * @param t the template to be used as a macro
113 */
114 public MacroTemplate (Context c, Template t)
115 {
116 _template = t;
117 _origContext = c;
118
119 _context = c.cloneContext();
120 }
121
122 /*** Construct a MacroTemplate with a StringTemplate
123 * @param c The context of the current request
124 * @param src the string for the StringTemplate
125 */
126 public MacroTemplate (Context c, String src)
127 {
128 this(c, new StringTemplate(c.getBroker(), src));
129 }
130
131 /*** Exposes the context of the current MacroTemplate. This allows
132 * "arguments" to be set from a template. E.g.,
133 * <CODE>#set $myMacro.Args.Name = $User.Name</CODE>
134 * @return the context of the macro
135 */
136 public Context getArgs ()
137 {
138 return _context;
139 }
140
141 /*** Evaluates the macro's template against its context and returns the
142 * resulting string.
143 * @throws PropertyException runtime errors in evaluating the macro's template
144 * @return the resultant string after the template is evaluated.
145 */
146 public Object eval () throws PropertyException
147 {
148 synchronized (_context)
149 {
150 return _template.evaluateAsString(_context);
151 }
152 }
153
154 public Object eval (Object[] args) throws PropertyException
155 {
156 if (args != null)
157 {
158 for (int i = 0; i < args.length; i++)
159 {
160 _context.put("arg" + (i + 1), args[i]);
161 }
162 _context.put("args", args);
163 }
164 return eval();
165 }
166
167 public Object eval (Object[] args, Object[] names) throws PropertyException
168 {
169 if (args == null || names == null || args.length != names.length)
170 throw new PropertyException(
171 "Usage error: both args must be arrays of equal length!");
172 for (int i = 0; i < args.length; i++)
173 {
174 _context.put(names[i], args[i]);
175 }
176 _context.put("args", args);
177 return eval();
178 }
179
180 public Object eval (java.util.Map map) throws PropertyException
181 {
182 _context.putAll(map);
183 return eval();
184 }
185
186 /*** Copies all variables from the current request context into the context
187 * of the macro.
188 */
189 public void copyCurrentContext ()
190 {
191 synchronized (_context)
192 {
193 _context.putAll(_origContext);
194 }
195 }
196
197 }
198 }
199