All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.velocity.app.event.EventCartridge Maven / Gradle / Ivy

The newest version!
package org.apache.velocity.app.event;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import org.apache.velocity.context.Context;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.context.InternalEventContext;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.util.RuntimeServicesAware;
import org.apache.velocity.util.introspection.Info;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 

Stores the event handlers. Event handlers can be assigned on a per * VelocityEngine instance basis by specifying the class names in the * velocity.properties file. Event handlers may also be assigned on a per-page * basis by creating a new instance of EventCartridge, adding the event * handlers, and then calling attachToContext. For clarity, it's recommended * that one approach or the other be followed, as the second method is primarily * presented for backwards compatibility.

*

Note that Event Handlers follow a filter pattern, with multiple event * handlers allowed for each event. When the appropriate event occurs, all the * appropriate event handlers are called in the sequence they were added to the * Event Cartridge. See the javadocs of the specific event handler interfaces * for more details.

* * @author Will Glass-Husain * @author Geir Magnusson Jr. * @author Jose Alberto Fernandez * @version $Id$ */ public class EventCartridge { private List referenceHandlers = new ArrayList<>(); private MethodExceptionEventHandler methodExceptionHandler = null; private List includeHandlers = new ArrayList<>(); private List invalidReferenceHandlers = new ArrayList<>(); /** * Ensure that handlers are not initialized more than once. */ Set initializedHandlers = new HashSet<>(); protected RuntimeServices rsvc = null; protected Logger getLog() { return rsvc == null ? LoggerFactory.getLogger(EventCartridge.class) : rsvc.getLog(); } /** * runtime services setter, called during initialization * * @param rs runtime services * @since 2.0 */ public synchronized void setRuntimeServices(RuntimeServices rs) { if (rsvc == null) { rsvc = rs; /* allow for this method to be called *after* adding event handlers */ for (EventHandler handler : referenceHandlers) { if (handler instanceof RuntimeServicesAware && !initializedHandlers.contains(handler)) { ((RuntimeServicesAware) handler).setRuntimeServices(rs); initializedHandlers.add(handler); } } if (methodExceptionHandler != null && methodExceptionHandler instanceof RuntimeServicesAware && !initializedHandlers.contains(methodExceptionHandler)) { ((RuntimeServicesAware) methodExceptionHandler).setRuntimeServices(rs); initializedHandlers.add(methodExceptionHandler); } for (EventHandler handler : includeHandlers) { if (handler instanceof RuntimeServicesAware && !initializedHandlers.contains(handler)) { ((RuntimeServicesAware) handler).setRuntimeServices(rs); initializedHandlers.add(handler); } } for (EventHandler handler : invalidReferenceHandlers) { if (handler instanceof RuntimeServicesAware && !initializedHandlers.contains(handler)) { ((RuntimeServicesAware) handler).setRuntimeServices(rs); initializedHandlers.add(handler); } } } else if (rsvc != rs) { throw new VelocityException("an event cartridge cannot be used by several different runtime services instances"); } } /** * Adds an event handler(s) to the Cartridge. This method * will find all possible event handler interfaces supported * by the passed in object. * * @param ev object implementing a valid EventHandler-derived interface * @return true if a supported interface, false otherwise or if null */ public boolean addEventHandler(EventHandler ev) { if (ev == null) { return false; } boolean found = false; if (ev instanceof ReferenceInsertionEventHandler) { addReferenceInsertionEventHandler((ReferenceInsertionEventHandler) ev); found = true; } if (ev instanceof MethodExceptionEventHandler) { addMethodExceptionHandler((MethodExceptionEventHandler) ev); found = true; } if (ev instanceof IncludeEventHandler) { addIncludeEventHandler((IncludeEventHandler) ev); found = true; } if (ev instanceof InvalidReferenceEventHandler) { addInvalidReferenceEventHandler((InvalidReferenceEventHandler) ev); found = true; } if (found && rsvc != null && ev instanceof RuntimeServicesAware && !initializedHandlers.contains(ev)) { ((RuntimeServicesAware) ev).setRuntimeServices(rsvc); initializedHandlers.add(ev); } return found; } /** * Add a reference insertion event handler to the Cartridge. * * @param ev ReferenceInsertionEventHandler * @since 1.5 */ public void addReferenceInsertionEventHandler(ReferenceInsertionEventHandler ev) { referenceHandlers.add(ev); } /** * Add a method exception event handler to the Cartridge. * * @param ev MethodExceptionEventHandler * @since 1.5 */ public void addMethodExceptionHandler(MethodExceptionEventHandler ev) { if (methodExceptionHandler == null) { methodExceptionHandler = ev; } else { getLog().warn("ignoring extra method exception handler"); } } /** * Add an include event handler to the Cartridge. * * @param ev IncludeEventHandler * @since 1.5 */ public void addIncludeEventHandler(IncludeEventHandler ev) { includeHandlers.add(ev); } /** * Add an invalid reference event handler to the Cartridge. * * @param ev InvalidReferenceEventHandler * @since 1.5 */ public void addInvalidReferenceEventHandler(InvalidReferenceEventHandler ev) { invalidReferenceHandlers.add(ev); } /** * Removes an event handler(s) from the Cartridge. This method will find all * possible event handler interfaces supported by the passed in object and * remove them. * * @param ev object impementing a valid EventHandler-derived interface * @return true if event handler was previously registered, false if not * found */ public boolean removeEventHandler(EventHandler ev) { if (ev == null) { return false; } if (ev instanceof ReferenceInsertionEventHandler) { return referenceHandlers.remove(ev); } if (ev instanceof MethodExceptionEventHandler) { if (ev == methodExceptionHandler) { methodExceptionHandler = null; return true; } } if (ev instanceof IncludeEventHandler) { return includeHandlers.remove(ev); } if (ev instanceof InvalidReferenceEventHandler) { return invalidReferenceHandlers.remove(ev); } return false; } /** * Call reference insertion handlers * @param context * @param reference * @param value * @return value returned by handlers * @since 2.0 */ public Object referenceInsert(InternalContextAdapter context, String reference, Object value) { for (ReferenceInsertionEventHandler handler : referenceHandlers) { value = handler.referenceInsert(context, reference, value); } return value; } /** * Check whether this event cartridge has a method exception event handler * * @return true if a method exception event handler has been registered * @since 2.0 */ boolean hasMethodExceptionEventHandler() { return methodExceptionHandler != null; } /** * Call method exception event handler * @param context * @param claz * @param method * @param e exception * @param info template name, line and column infos * @return value returned by handler * @since 2.0 */ public Object methodException(Context context, Class claz, String method, Exception e, Info info) { if (methodExceptionHandler != null) { return methodExceptionHandler.methodException(context, claz, method, e, info); } return null; } /** * Call include event handlers * * @param context * @param includeResourcePath * @param currentResourcePath * @param directiveName * @return include path * @since 2.0 */ public String includeEvent(Context context, String includeResourcePath, String currentResourcePath, String directiveName) { for (IncludeEventHandler handler : includeHandlers) { includeResourcePath = handler.includeEvent(context, includeResourcePath, currentResourcePath, directiveName); /* reflect 1.x behavior: exit after at least one execution whenever a null include path has been found */ if (includeResourcePath == null) { break; } } return includeResourcePath; } /** * Call invalid reference handlers for an invalid getter * * @param context * @param reference * @param object * @param property * @param info * @return value returned by handlers * @since 2.0 */ public Object invalidGetMethod(Context context, String reference, Object object, String property, Info info) { Object result = null; for (InvalidReferenceEventHandler handler : invalidReferenceHandlers) { result = handler.invalidGetMethod(context, reference, object, property, info); /* reflect 1.x behavior: exit after at least one execution whenever a non-null value has been found */ if (result != null) { break; } } return result; } /** * Call invalid reference handlers for an invalid setter * * @param context * @param leftreference * @param rightreference * @param info * @return whether to stop further chaining in the next cartridge * @since 2.0 */ public boolean invalidSetMethod(Context context, String leftreference, String rightreference, Info info) { for (InvalidReferenceEventHandler handler : invalidReferenceHandlers) { if (handler.invalidSetMethod(context, leftreference, rightreference, info)) { return true; } } return false; } /** * Call invalid reference handlers for an invalid method call * * @param context * @param reference * @param object * @param method * @param info * @return value returned by handlers * @since 2.0 */ public Object invalidMethod(Context context, String reference, Object object, String method, Info info) { Object result = null; for (InvalidReferenceEventHandler handler : invalidReferenceHandlers) { result = handler.invalidMethod(context, reference, object, method, info); /* reflect 1.x behavior: exit after at least one execution whenever a non-null value has been found */ if (result != null) { break; } } return result; } /** * Attached the EventCartridge to the context * * Final because not something one should mess with lightly :) * * @param context context to attach to * @return true if successful, false otherwise */ public final boolean attachToContext(Context context) { if (context instanceof InternalEventContext) { InternalEventContext iec = (InternalEventContext) context; iec.attachEventCartridge(this); /* * while it's tempting to call setContext on each handler from here, * this needs to be done before each method call. This is * because the specific context will change as inner contexts * are linked in through macros, foreach, or directly by the user. */ return true; } else { return false; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy