org.apache.juneau.svl.Var Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * 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. *
// ***************************************************************************************************************************
package org.apache.juneau.svl;
import static org.apache.juneau.internal.ThrowableUtils.*;
import java.io.*;
/**
* Abstract superclass of all Simple Var Language variables.
*
*
* Vars are used to convert simple variables of the form "$varName{varKey}" into something else by the
* {@link VarResolver} class.
*
*
* Subclasses must implement one of the following two methods:
*
* - {@link #resolve(VarResolverSession,String)} - For simple vars.
*
- {@link #resolveTo(VarResolverSession,Writer,String)} - For streamed vars.
*
*
*
* Subclasses MUST implement a no-arg constructor so that class names can be passed to the
* {@link VarResolverBuilder#vars(Class...)} method.
*
They must also be thread safe!
*
*
* Two direct abstract subclasses are provided to differentiated between simple and streamed vars:
*
* - {@link SimpleVar}
*
- {@link StreamedVar}
*
*
* See Also:
*
* - {@doc juneau-svl.SvlVariables}
*
*/
public abstract class Var {
private final String name;
final boolean streamed;
/**
* Constructor.
*
* @param name The name of this variable.
* @param streamed
* Whether this variable is 'streamed', meaning the {@link #resolveTo(VarResolverSession, Writer, String)} method
* is implemented.
* If false , then the {@link #resolve(VarResolverSession, String)} method is implemented.
*/
public Var(String name, boolean streamed) {
this.name = name;
this.streamed = streamed;
if (name == null)
illegalArg("Invalid var name. Must consist of only uppercase and lowercase ASCII letters.");
else for (int i = 0; i < name.length(); i++) {
// Need to make sure only ASCII characters are used.
char c = name.charAt(i);
if (c < 'A' || c > 'z' || (c > 'Z' && c < 'a'))
illegalArg("Invalid var name. Must consist of only uppercase and lowercase ASCII letters.");
}
}
/**
* Return the name of this variable.
*
*
* For example, the system property variable returns "S" since the format of the variable is
* "$S{system.property}" .
*
* @return The name of this variable.
*/
protected String getName() {
return name;
}
/**
* Returns whether nested variables are supported by this variable.
*
*
* For example, in "$X{$Y{xxx}}" , $Y is a nested variable that will be resolved if this method returns
* true .
*
*
* The default implementation of this method always returns true .
* Subclasses can override this method to override the default behavior.
*
* @return true if nested variables are supported by this variable.
*/
protected boolean allowNested() {
return true;
}
/**
* Returns whether variables in the resolved contents of this variable should also be resolved.
*
*
* For example, if "$X{xxx}" resolves to "$Y{xxx}" , then the $Y variable will be recursively
* resolved if this method returns true .
*
*
* The default implementation of this method always returns true .
*
Subclasses can override this method to override the default behavior.
*
*
Important Note
*
* As a general rule, variables that resolve user-entered data should not be recursively resolved as this may
* cause a security hole.
*
* @return true if resolved variables should be recursively resolved.
*/
protected boolean allowRecurse() {
return true;
}
/**
* The method called from {@link VarResolver}.
*
*
* Can be overridden to intercept the request and do special handling.
*
Default implementation simply calls resolve(String).
*
* @param session The session object used for a single instance of a string resolution.
* @param arg The inside argument of the variable.
* @return The resolved value.
* @throws Exception Any exception can be thrown.
*/
protected String doResolve(VarResolverSession session, String arg) throws Exception {
return resolve(session, arg);
}
/**
* The interface that needs to be implemented for subclasses of {@link SimpleVar}.
*
* @param session The session object used for a single instance of a var resolution.
* @param arg The inside argument of the variable.
* @return The resolved value.
* @throws Exception Any exception can be thrown.
*/
public abstract String resolve(VarResolverSession session, String arg) throws Exception;
/**
* The interface that needs to be implemented for subclasses of {@link StreamedVar}.
*
* @param session The session object used for a single instance of a var resolution.
* @param w The writer to send the resolved value to.
* @param arg The inside argument of the variable.
* @throws Exception Any exception can be thrown.
*/
public abstract void resolveTo(VarResolverSession session, Writer w, String arg) throws Exception;
}