001: package org.apache.velocity.test;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.StringWriter;
023: import java.io.Writer;
024:
025: import junit.framework.Test;
026: import junit.framework.TestCase;
027: import junit.framework.TestSuite;
028:
029: import org.apache.velocity.VelocityContext;
030: import org.apache.velocity.app.VelocityEngine;
031: import org.apache.velocity.app.event.EventCartridge;
032: import org.apache.velocity.app.event.MethodExceptionEventHandler;
033: import org.apache.velocity.app.event.NullSetEventHandler;
034: import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
035: import org.apache.velocity.context.Context;
036: import org.apache.velocity.exception.MethodInvocationException;
037: import org.apache.velocity.runtime.RuntimeConstants;
038: import org.apache.velocity.runtime.RuntimeServices;
039: import org.apache.velocity.runtime.log.LogChute;
040: import org.apache.velocity.util.ContextAware;
041: import org.apache.velocity.util.RuntimeServicesAware;
042:
043: /**
044: * Tests event handling for all event handlers except IncludeEventHandler. This is tested
045: * separately due to its complexity.
046: *
047: * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
048: * @version $Id: EventHandlingTestCase.java 463298 2006-10-12 16:10:32Z henning $
049: */
050: public class EventHandlingTestCase extends TestCase implements LogChute {
051: private static String NO_REFERENCE_VALUE = "<no reference value>";
052: private static String REFERENCE_VALUE = "<reference value>";
053:
054: private static String logString = null;
055:
056: /**
057: * Default constructor.
058: */
059: public EventHandlingTestCase(String name) {
060: super (name);
061: }
062:
063: public static Test suite() {
064: return new TestSuite(EventHandlingTestCase.class);
065: }
066:
067: public void testManualEventHandlers() throws Exception {
068: TestEventCartridge te = new TestEventCartridge();
069: /**
070: * Test attaching the event cartridge to the context
071: */
072: VelocityEngine ve = new VelocityEngine();
073: ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, this );
074: ve.init();
075:
076: /*
077: * lets make a Context and add the event cartridge
078: */
079:
080: VelocityContext inner = new VelocityContext();
081:
082: /*
083: * Now make an event cartridge, register all the
084: * event handlers (at once) and attach it to the
085: * Context
086: */
087:
088: EventCartridge ec = new EventCartridge();
089: ec.addEventHandler(te);
090: ec.attachToContext(inner);
091:
092: /*
093: * now wrap the event cartridge - we want to make sure that
094: * we can do this w/o harm
095: */
096:
097: doTestReferenceInsertionEventHandler1(ve, inner);
098: doTestReferenceInsertionEventHandler2(ve, inner);
099: doTestNullValueEventHandler(ve, inner);
100: doTestSetNullValueEventHandler(ve, inner);
101: doTestMethodExceptionEventHandler1(ve, inner);
102: doTestMethodExceptionEventHandler2(ve, inner);
103: }
104:
105: /**
106: * Test assigning the event handlers via properties
107: */
108:
109: public void testConfigurationEventHandlers() throws Exception {
110: VelocityEngine ve = new VelocityEngine();
111: ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, this );
112: ve.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION,
113: TestEventCartridge.class.getName());
114: ve.setProperty(RuntimeConstants.EVENTHANDLER_NULLSET,
115: TestEventCartridge.class.getName());
116: ve.setProperty(
117: RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION,
118: TestEventCartridge.class.getName());
119:
120: ve.init();
121:
122: doTestReferenceInsertionEventHandler1(ve, null);
123: doTestReferenceInsertionEventHandler2(ve, null);
124: doTestNullValueEventHandler(ve, null);
125: doTestSetNullValueEventHandler(ve, null);
126: doTestMethodExceptionEventHandler1(ve, null);
127: doTestMethodExceptionEventHandler2(ve, null);
128: }
129:
130: /**
131: * Test all the event handlers using the given engine.
132: * @param ve
133: * @param vcontext
134: */
135: private void doTestReferenceInsertionEventHandler1(
136: VelocityEngine ve, VelocityContext vc) throws Exception {
137: VelocityContext context = new VelocityContext(vc);
138:
139: context.put("name", "Velocity");
140:
141: /*
142: * First, the reference insertion handler
143: */
144:
145: String s = "$name$name$name";
146:
147: StringWriter w = new StringWriter();
148: ve.evaluate(context, w, "mystring", s);
149:
150: if (!w.toString().equals(
151: REFERENCE_VALUE + REFERENCE_VALUE + REFERENCE_VALUE)) {
152: fail("Reference insertion test 1");
153: }
154: }
155:
156: private void doTestReferenceInsertionEventHandler2(
157: VelocityEngine ve, VelocityContext vc) throws Exception {
158: VelocityContext context = new VelocityContext(vc);
159: context.put("name", "Velocity");
160:
161: /*
162: * using the same handler, we can deal with
163: * null references as well
164: */
165:
166: String s = "$floobie";
167:
168: Writer w = new StringWriter();
169: ve.evaluate(context, w, "mystring", s);
170:
171: if (!w.toString().equals(NO_REFERENCE_VALUE)) {
172: fail("Reference insertion test 2");
173: }
174: }
175:
176: private void doTestNullValueEventHandler(VelocityEngine ve,
177: VelocityContext vc) throws Exception {
178: VelocityContext context = new VelocityContext(vc);
179:
180: /*
181: * now lets test setting a null value - this test
182: * should result in *no* log output.
183: */
184:
185: String s = "#set($settest = $NotAReference)";
186: Writer w = new StringWriter();
187: clearLogString();
188: ve.evaluate(context, w, "mystring", s);
189:
190: if (getLogString() != null) {
191: fail("NullSetEventHandler test 1");
192: }
193: }
194:
195: private void doTestSetNullValueEventHandler(VelocityEngine ve,
196: VelocityContext vc) throws Exception {
197: VelocityContext context = new VelocityContext(vc);
198:
199: /*
200: * now lets test setting a null value - this test
201: * should result in log output.
202: */
203:
204: String s = "#set($logthis = $NotAReference)";
205: Writer w = new StringWriter();
206: clearLogString();
207: ve.evaluate(context, w, "mystring", s);
208:
209: if (getLogString() == null) {
210: fail("NullSetEventHandler test 2");
211: }
212: }
213:
214: private void doTestMethodExceptionEventHandler1(VelocityEngine ve,
215: VelocityContext vc) throws Exception {
216: VelocityContext context = new VelocityContext(vc);
217:
218: /*
219: * finally, we test a method exception event - we do this
220: * by putting this class in the context, and calling
221: * a method that does nothing but throw an exception.
222: * we use flag in the context to turn the event handling
223: * on and off
224: *
225: * Note also how the reference insertion process
226: * happens as well
227: */
228:
229: context.put("allow_exception", Boolean.TRUE);
230:
231: context.put("this", this );
232:
233: String s = " $this.throwException()";
234: Writer w = new StringWriter();
235:
236: ve.evaluate(context, w, "mystring", s);
237: }
238:
239: private void doTestMethodExceptionEventHandler2(VelocityEngine ve,
240: VelocityContext vc) throws Exception {
241: VelocityContext context = new VelocityContext(vc);
242: context.put("this", this );
243:
244: /*
245: * now, we remove the exception flag, and we can see that the
246: * exception will propgate all the way up here, and
247: * wil be caught by the catch() block below
248: */
249:
250: String s = " $this.throwException()";
251: Writer w = new StringWriter();
252:
253: try {
254: ve.evaluate(context, w, "mystring", s);
255: fail("No MethodExceptionEvent received!");
256: } catch (MethodInvocationException mee) {
257: // Do nothing
258: }
259: }
260:
261: /**
262: * silly method to throw an exception to test
263: * the method invocation exception event handling
264: */
265: public void throwException() throws Exception {
266: throw new Exception("Hello from throwException()");
267: }
268:
269: /**
270: * Required by LogChute
271: */
272: public void init(RuntimeServices rs) {
273: /* don't need it...*/
274: }
275:
276: /**
277: * handler for LogChute interface
278: */
279: public void log(int level, String message) {
280: setLogString(message);
281: }
282:
283: public void log(int level, String message, Throwable t) {
284: setLogString(message);
285: }
286:
287: public boolean isLevelEnabled(int level) {
288: return true;
289: }
290:
291: public static void clearLogString() {
292: logString = null;
293: }
294:
295: public static void setLogString(String message) {
296: logString = message;
297: }
298:
299: public static String getLogString() {
300: return logString;
301: }
302:
303: public static class TestEventCartridge implements
304: ReferenceInsertionEventHandler, NullSetEventHandler,
305: MethodExceptionEventHandler, RuntimeServicesAware,
306: ContextAware {
307: private RuntimeServices rs;
308:
309: public TestEventCartridge() {
310: }
311:
312: /**
313: * Required by EventHandler
314: */
315: public void setRuntimeServices(RuntimeServices rs) {
316: // make sure this is only called once
317: if (this .rs == null)
318: this .rs = rs;
319:
320: else
321: fail("initialize called more than once.");
322: }
323:
324: /**
325: * Event handler for when a reference is inserted into the output stream.
326: */
327: public Object referenceInsert(String reference, Object value) {
328: // as a test, make sure this EventHandler is initialized
329: if (rs == null)
330: fail("Event handler not initialized!");
331:
332: /*
333: * if we have a value
334: * return a known value
335: */
336: String s = null;
337:
338: if (value != null) {
339: s = REFERENCE_VALUE;
340: } else {
341: /*
342: * we only want to deal with $floobie - anything
343: * else we let go
344: */
345: if (reference.equals("$floobie")) {
346: s = NO_REFERENCE_VALUE;
347: }
348: }
349: return s;
350: }
351:
352: /**
353: * Event handler for when the right hand side of
354: * a #set() directive is null, which results in
355: * a log message. This method gives the application
356: * a chance to 'vote' on msg generation
357: */
358: public boolean shouldLogOnNullSet(String lhs, String rhs) {
359: // as a test, make sure this EventHandler is initialized
360: if (rs == null)
361: fail("Event handler not initialized!");
362:
363: if (lhs.equals("$settest"))
364: return false;
365:
366: return true;
367: }
368:
369: /**
370: * Handles exceptions thrown during in-template method access
371: */
372: public Object methodException(Class claz, String method,
373: Exception e) throws Exception {
374: // as a test, make sure this EventHandler is initialized
375: if (rs == null)
376: fail("Event handler not initialized!");
377:
378: // only do processing if the switch is on
379: if (context != null) {
380: boolean exceptionSwitch = context
381: .containsKey("allow_exception");
382:
383: if (exceptionSwitch && method.equals("throwException")) {
384: return "handler";
385: } else
386: throw e;
387:
388: } else
389:
390: throw e;
391: }
392:
393: Context context;
394:
395: public void setContext(Context context) {
396: this.context = context;
397: }
398: }
399: }
|