Skip to content

Latest commit

 

History

History
148 lines (133 loc) · 11.9 KB

ExtensionContext.md

File metadata and controls

148 lines (133 loc) · 11.9 KB

Extension context

Extension Context is a mechanism dedicated to call Java code from selectors. In order to fully use this mechanism, the Extended Evaluate Selector is recommended (as this plugin is able to relay CircuitAbortException).

If not using the Filter Devkit loadable module the following limitations apply :

  • Only static method export allowed,
  • No global namespace registration (explicit reflection of Java classes within groovies),
  • No 'child first' class loader available (depends on Extension interface).

There is 3 kinds of exported methods

  • Invocable method : invoke a Java method like a policy shortcut using an (Extended) Eval Selector Filter. Parameters are resolved from annotations and injected.
  • Substitutable method : invoke a Java method to return any value. This kind of export can't throw exceptions but can be used anywhere in the API Gateway where selectors are accepted (Set Message, Copy/Modify, Set Attribute, etc...). Parameters are resolved from annotations and injected.
  • Extension Function : Invoke a Java method using JUEL invoke syntax. Parameters must be provided in the JUEL expression. Use with caution since parameter coercion may be tricky and variable arguments can cause strange behavior when used outside of Java Strong typing system (like Javascript or JUEL).

Extension context global registration use an API Gateway global namespace. This global registration is only available when using the Filter Devkit module has been imported in the typeset. Script exported contexts do not use the global namespace they use a message attribute instead. See examples below for global registration.

// syntax for invocable where name is the extension name and exportedInvocable the exported method
${extensions['name'].exportedInvocable}
// syntax for substitutable where name is the extension name and exportedSubstitutable the exported method
${extensions['name'].exportedSubstitutable}
// syntax for function where name is the extension name and exportedFunction the exported method
// arguments are also JUEL expressions
${extensions['name'].exportedFunction(arg1, arg2, arg3}

Reflection rules :

For implementing :

For groovy scripts contexts ExtensionContext and ExtensionInstance are not needed. The script is always an instance and a runtime function is provided to reflect exported methods. Also ExtensionLibraries is not available for Groovy.

Here is an example implementation (instanciated) :

import com.vordel.circuit.CircuitAbortException;
import com.vordel.circuit.Message;
import com.vordel.circuit.filter.devkit.context.annotations.DictionaryAttribute;
import com.vordel.circuit.filter.devkit.context.annotations.ExtensionContext;
import com.vordel.circuit.filter.devkit.context.annotations.ExtensionFunction;
import com.vordel.circuit.filter.devkit.context.annotations.ExtensionInstance;
import com.vordel.circuit.filter.devkit.context.annotations.InvocableMethod;
import com.vordel.circuit.filter.devkit.context.annotations.SelectorExpression;
import com.vordel.circuit.filter.devkit.context.annotations.SubstitutableMethod;
import com.vordel.common.Dictionary;

/**
 * sample extension context for API Gateway. This extension will get registered
 * under the 'sample' name. The @ExtensionInstance annotation allows this class
 * to be instanciated with the no-arg constructor (but it will not register any
 * interface). Since it does not implements ExtensionModule, there will be no
 * attachModule() or detachModule() initialization calls.
 * 
 * Without @ExtensionInstance all exported methods must be set as static
 */
@ExtensionInstance
@ExtensionContext("sample")
public class ExtensionContextSample {
	/**
	 * example export for a invocable method. all parameters are injected
	 * 
	 * @param msg  current message
	 * @param arg1 the message attribute 'attr1' will be retrieved from the message
	 *             and coerced to requested type (String)
	 * @param arg2 the selector expression ${attr2} will be applied on the message
	 *             and coerced to requested type (String)
	 * @return always true
	 * @throws CircuitAbortException if any error occurs
	 */
	@InvocableMethod
	public boolean invokeTest(Message msg, @DictionaryAttribute("attr1") String arg1, @SelectorExpression("attr2") String arg2) throws CircuitAbortException {
		// call this method with ${extensions['sample'].invokeTest}
		return true;
	}

	/**
	 * example export for a substitutable method. all parameters are injected. The
	 * annotation have defined export name which will be used instead of the method
	 * name.
	 * 
	 * @param msg  should be current message (when called outside script), but can
	 *             be null since script invocation allows to use Dictionary instead
	 * @param dict selector dictionary (generally this is the current message)
	 * @param arg1 the message attribute 'attr1' will be retrieved from the
	 *             dictionary and coerced to requested type (String)
	 * @param arg2 the selector expression ${attr2} will be applied on the
	 *             dictionary and coerced to requested type (String)
	 * @return "hello" constant
	 */
	@SubstitutableMethod("substituteTest")
	public String sayHello(Message msg, Dictionary dict, @DictionaryAttribute("attr1") String arg1, @SelectorExpression("attr2") String arg2) {
		// call this method with ${extensions['sample'].substituteTest}
		return "hello";
	}

	/**
	 * example export for a function call. Only the first parameter is injected (can
	 * be Message or Dictionary). If Dictionary if provided in a script and Message
	 * is requested in the call, null will be provided as first argument. This
	 * example is typically used in an (Extended) Eval Selector.
	 * 
	 * @param msg  current message (when called outside script)
	 * @param arg1 provided and coerced to requested value using JUEL expression
	 * @param arg2 provided and coerced to requested value using JUEL expression
	 * @param arg3 provided and coerced to requested value using JUEL expression
	 * @return always true
	 * @throws CircuitAbortException if any error occurs
	 */
	@ExtensionFunction
	public boolean functionTest(Message msg, String arg1, String arg2, String arg3) throws CircuitAbortException {
		// call this method with ${extensions['sample'].functionTest(arg1, arg2, arg3)}
		return true;
	}

	/**
	 * example export for a function call. Only the first parameter is injected (can
	 * be Message or Dictionary). If Dictionary if provided in a script and Message
	 * is requested in the call, null will be provided as first argument. This
	 * example is typically used in an Set Message Filter.
	 * 
	 * @param msg  current message (when called outside script)
	 * @param name use name to saye hello
	 * @return say hello to given name
	 * @throws CircuitAbortException
	 */
	@ExtensionFunction
	public String sayHello(Message msg, String name) throws CircuitAbortException {
		// call this method with ${extensions['sample'].sayHello(http.querystring.name)}
		return String.format("Hello %s !", name);
	}
}