VariableManager.java
/*
* Copyright (C) 2002-2003,2017-2023 Dipl.-Inform. Kai Hofmann. All rights reserved!
*/
package de.powerstat.phplib.templateengine.intern;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Template variable manager.
*/
public final class VariableManager
{
/**
* Logger.
*/
private static final Logger LOGGER = LogManager.getLogger(VariableManager.class);
/**
* Template matcher regexp pattern.
*/
private static final Pattern TEMPLATE_MATCHER_REGEXP = Pattern.compile("\\{([^{^}\n\r\t :]+)\\}"); //$NON-NLS-1$
/**
* Block matcher regexp.
*/
private static final Pattern BLOCK_MATCHER_REGEXP = Pattern.compile("\\{([^ \\t\\r\\n}]+)\\}"); //$NON-NLS-1$
/**
* Temporary variables map.
*/
private final Map<String, String> vars = new ConcurrentHashMap<>();
/**
* Copy constructor.
*
* @param vManager Variable manager to copy from
* @throws NullPointerException If vManager is null
*/
public VariableManager(final VariableManager vManager)
{
super();
Objects.requireNonNull(vManager, "vManager"); //$NON-NLS-1$
for (final Map.Entry<String, String> entry : vManager.vars.entrySet())
{
this.vars.put(entry.getKey(), entry.getValue());
}
}
/**
* Default constructor.
*/
public VariableManager()
{
super();
}
/**
* Exists variable.
*
* @param varname Variable name
* @return true: Variable exists; false otherwise
*/
public boolean existsVar(final String varname)
{
return this.vars.containsKey(varname);
}
/**
* Get template variable value.
*
* @param varname Template variable name
* @return Template variables value
* @throws NullPointerException If varname is null
* @throws IllegalArgumentException If varname is empty
*/
public String getVar(final String varname)
{
final String value = this.vars.get(varname);
return (value == null) ? "" : value; //$NON-NLS-1$
}
/**
* Set template variables value.
*
* @param varname Template variable name
* @param value Template variable value, could be null
* @throws NullPointerException If varname is null
* @throws IllegalArgumentException If varname is empty
*/
public void setVar(final String varname, final String value)
{
// if (!value.matches("^.+$"))
this.vars.put(varname, (value == null) ? "" : value); //$NON-NLS-1$
}
/**
* Unset template variable.
*
* @param varname Template variable name
* @throws NullPointerException If varname is null
* @throws IllegalArgumentException If varname is empty
*/
@SuppressWarnings("java:S1120")
public void unsetVar(final String varname)
{
/* String value = */ this.vars.remove(varname);
}
/**
* Get list with all undefined template variables.
*
* @param varname Variable to parse for undefined variables
* @return List with undefined template variables names
* @throws NullPointerException If varname is null
* @throws IllegalArgumentException If varname is empty
*/
public List<String> getUndefined(final String varname)
{
// TODO asserts
final var matcher = VariableManager.BLOCK_MATCHER_REGEXP.matcher(getVar(varname));
boolean result = matcher.find();
final List<String> undefvars = new ArrayList<>();
while (result)
{
final String vname = matcher.group(1);
if (!this.vars.containsKey(vname) && !undefvars.contains(vname))
{
undefvars.add(vname);
}
result = matcher.find();
}
return Collections.unmodifiableList(undefvars);
}
/* *
* Replace variables old version.
*
* @param block Template block
* @return Template/Block with replaced variables
*/
/*
private String replaceVarsOld(String block)
{
assert (block != null) && !block.isEmpty();
// loop over all known variables an replace them
if (!this.vars.isEmpty())
{
final Set<Entry<String, String>> tempVarsSet = this.vars.entrySet();
for (Entry<String, String> mapEntry : tempVarsSet)
{
// convert into regexp (special char filter)
block = Pattern.compile("\\{" + mapEntry.getKey() + "\\}").matcher(block).replaceAll(mapEntry.getValue()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return block;
}
*/
/**
* Replace variables new version.
*
* @param block Template block
* @return Template/Block with replaced variables
*/
private String replaceVarsNew(final String block)
{
// assert (block != null) && !block.isEmpty();
// assert block.matches("^.+$")
// Get variable names to replace from varname
final var matcherTemplate = VariableManager.TEMPLATE_MATCHER_REGEXP.matcher(block);
final Set<String> varsSetTemplate = new TreeSet<>();
while (matcherTemplate.find())
{
final var varnameTemplate = block.substring(matcherTemplate.start() + 1, matcherTemplate.end() - 1);
if (this.vars.containsKey(varnameTemplate))
{
varsSetTemplate.add(varnameTemplate);
}
}
String resBlock = block;
for (final String varName : varsSetTemplate)
{
resBlock = resBlock.replaceAll("\\{" + varName + "\\}", getVar(varName)); //$NON-NLS-1$ //$NON-NLS-2$
}
return resBlock;
}
/**
* Substitute variable with its content.
*
* @param varname Variable name
* @return Replaced variable content or empty string
* @throws NullPointerException If varname is null
* @throws IllegalArgumentException If varname is empty
*/
public String subst(final String varname)
{
// return replaceVarsOld(getVar(varname));
return replaceVarsNew(getVar(varname));
}
/**
* Parse a variable and replace all variables within it by their content.
*
* @param target Target for parsing operation
* @param varname Parse the content of this variable
* @param append true for appending blocks to target, otherwise false for replacing targets content
* @return Variables content after parsing
* @throws NullPointerException If target or varname is null
* @throws IllegalArgumentException If target or varname is empty
*/
@SuppressWarnings("java:S2301")
public String parse(final String target, final String varname, final boolean append)
{
LOGGER.debug("varname: {}", varname);
final String str = subst(varname);
LOGGER.debug("str: {}", str);
setVar(target, (append ? getVar(target) : "") + str); //$NON-NLS-1$
return str;
}
/**
* Get list of all template variables.
*
* @return Array with names of template variables
*/
public List<String> getVars()
{
if (this.vars.isEmpty())
{
return Collections.emptyList();
}
final List<String> result = new ArrayList<>(this.vars.size());
for (final Entry<String, String> entry : this.vars.entrySet())
{
result.add(entry.getKey()); // entry.getValue();
}
return Collections.unmodifiableList(result);
}
/**
* Returns the string representation of this VariableManager.
*
* The exact details of this representation are unspecified and subject to change, but the following may be regarded as typical:
*
* " VariableManager[vars=[name, ...]]"
*
* @return String representation of this VariableManager.
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return new StringBuilder().append("VariableManager[vars=").append(getVars()).append(']').toString(); //$NON-NLS-1$
}
/**
* Calculate hash code.
*
* @return Hash
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
return Objects.hash(this.vars);
}
/**
* Is equal with another object.
*
* @param obj Object
* @return true when equal, false otherwise
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (!(obj instanceof VariableManager))
{
return false;
}
final VariableManager other = (VariableManager)obj;
return this.vars.equals(other.vars);
}
}