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&lt;Object&gt; <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}