001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.svl; 018 019import java.util.*; 020 021/** 022 * SPI for SVL {@code #{...}} script-evaluation functions. 023 * 024 * <p> 025 * A {@code VarFunction} is invoked when an SVL template contains a 026 * <c>#{name(arg1, arg2, ...)}</c> reference — distinct from {@code $X{...}} variables. Functions 027 * compose freely with {@code ${...}} lookups and other {@code #{...}} calls; arguments are 028 * pre-resolved by the runtime before {@link #invoke(VarResolverSession, List) invoke} is called. 029 * 030 * <h5 class='section'>Naming note:</h5> 031 * <p> 032 * Named {@code VarFunction} rather than the shorter {@code Function} because Juneau's 033 * serializer/parser/test code makes heavy use of {@link java.util.function.Function} and 034 * routinely co-imports {@code org.apache.juneau.commons.svl.*}; a bare {@code Function} type in 035 * this package would trigger ambiguous-reference errors across many callers. The chosen name 036 * also matches the existing {@code Var}/{@code VarResolver}/{@code VarTemplate}/{@code VarResolverSession} 037 * naming family. 038 * 039 * <p> 040 * Implementations can register through any of four discovery channels (later wins on name 041 * collision): 042 * <ol> 043 * <li>The built-in catalog auto-registered by {@link VarResolver#DEFAULT}. 044 * <li>{@code META-INF/services/org.apache.juneau.commons.svl.VarFunction} (Java {@link java.util.ServiceLoader}). 045 * <li>{@code BeanStore.getBeans(VarFunction.class)} on the resolver's bean store. 046 * <li>Explicit registrations via {@code VarResolver.Builder.functions(...)}. 047 * </ol> 048 * 049 * <p> 050 * For typed reflection-based dispatch (the recommended path), extend 051 * {@link TypedFunction} — it derives {@link #minArity()}, {@link #maxArity()}, and per-arg 052 * coercion automatically from the subclass's {@code invoke(...)} method signature, eliminating 053 * the per-function plumbing. 054 * 055 * <h5 class='section'>Example:</h5> 056 * <p class='bjava'> 057 * <jc>// Direct VarFunction impl (less common — TypedFunction is preferred).</jc> 058 * <jk>public class</jk> Reverse <jk>implements</jk> VarFunction { 059 * <ja>@Override</ja> <jk>public</jk> String name() { <jk>return</jk> <js>"reverse"</js>; } 060 * <ja>@Override</ja> <jk>public int</jk> minArity() { <jk>return</jk> 1; } 061 * <ja>@Override</ja> <jk>public int</jk> maxArity() { <jk>return</jk> 1; } 062 * <ja>@Override</ja> <jk>public</jk> String invoke(VarResolverSession <jv>session</jv>, List<Object> <jv>args</jv>) { 063 * <jk>return new</jk> StringBuilder((String) <jv>args</jv>.get(0)).reverse().toString(); 064 * } 065 * } 066 * </p> 067 * 068 * <h5 class='section'>See Also:</h5><ul> 069 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallSimpleVariableLanguage">Marshall Simple Variable Language</a> 070 * <li class='jc'>{@link TypedFunction} 071 * </ul> 072 */ 073public interface VarFunction { 074 075 /** 076 * The function's invocation name as it appears between {@code #{}} and the opening 077 * parenthesis in the template. Must consist of ASCII letters, digits, and underscores; must 078 * begin with a letter. 079 * 080 * @return The invocation name. Never {@code null} or empty. 081 */ 082 String name(); 083 084 /** 085 * Minimum argument count this function accepts. 086 * 087 * @return The minimum number of args. {@code 0} means the function may be called with no 088 * args. Returns {@code -1} for "any number of args" — equivalent to declaring 089 * {@code minArity == 0 && maxArity == Integer.MAX_VALUE}. 090 */ 091 int minArity(); 092 093 /** 094 * Maximum argument count this function accepts. 095 * 096 * @return The maximum number of args, or {@link Integer#MAX_VALUE} for unbounded variadic 097 * functions. 098 */ 099 int maxArity(); 100 101 /** 102 * Invokes this function with already-resolved, type-coerced arguments. 103 * 104 * <p> 105 * The runtime resolves each {@code #{...}} arg template against the session, then coerces 106 * the resolved string to the target Java type via {@code ArgCoercer}. The resulting 107 * {@code List<Object>} is passed in here. 108 * 109 * @param session The current resolver session. Must not be {@code null}. 110 * @param args The coerced arguments. Size is in {@code [minArity(), maxArity()]}. Each 111 * element is the type the function expects per its signature; for variadic / 112 * {@code Object}-typed slots, elements remain {@link String}. 113 * @return The function's result as a {@link String}. May be empty but should not be 114 * {@code null} (the runtime treats {@code null} as the empty string for SVL output). 115 */ 116 String invoke(VarResolverSession session, List<Object> args); 117}