View Javadoc
1   /*
2    * Copyright (C) 2002-2003,2017-2023 Dipl.-Inform. Kai Hofmann. All rights reserved!
3    */
4   package de.powerstat.phplib.templateengine.intern;
5   
6   
7   import java.util.ArrayList;
8   import java.util.Collections;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.Map.Entry;
12  import java.util.Objects;
13  import java.util.Set;
14  import java.util.TreeSet;
15  import java.util.concurrent.ConcurrentHashMap;
16  import java.util.regex.Pattern;
17  
18  import org.apache.logging.log4j.LogManager;
19  import org.apache.logging.log4j.Logger;
20  
21  
22  /**
23   * Template variable manager.
24   */
25  public final class VariableManager
26   {
27    /**
28     * Logger.
29     */
30    private static final Logger LOGGER = LogManager.getLogger(VariableManager.class);
31  
32    /**
33     * Template matcher regexp pattern.
34     */
35    private static final Pattern TEMPLATE_MATCHER_REGEXP = Pattern.compile("\\{([^{^}\n\r\t :]+)\\}"); //$NON-NLS-1$
36  
37    /**
38     * Block matcher regexp.
39     */
40    private static final Pattern BLOCK_MATCHER_REGEXP = Pattern.compile("\\{([^ \\t\\r\\n}]+)\\}"); //$NON-NLS-1$
41  
42    /**
43     * Temporary variables map.
44     */
45    private final Map<String, String> vars = new ConcurrentHashMap<>();
46  
47  
48    /**
49     * Copy constructor.
50     *
51     * @param vManager Variable manager to copy from
52     * @throws NullPointerException If vManager is null
53     */
54    public VariableManager(final VariableManager vManager)
55     {
56      super();
57      Objects.requireNonNull(vManager, "vManager"); //$NON-NLS-1$
58      for (final Map.Entry<String, String> entry : vManager.vars.entrySet())
59       {
60        this.vars.put(entry.getKey(), entry.getValue());
61       }
62     }
63  
64  
65    /**
66     * Default constructor.
67     */
68    public VariableManager()
69     {
70      super();
71     }
72  
73  
74    /**
75     * Exists variable.
76     *
77     * @param varname Variable name
78     * @return true: Variable exists; false otherwise
79     */
80    public boolean existsVar(final String varname)
81     {
82      return this.vars.containsKey(varname);
83     }
84  
85  
86    /**
87     * Get template variable value.
88     *
89     * @param varname Template variable name
90     * @return Template variables value
91     * @throws NullPointerException If varname is null
92     * @throws IllegalArgumentException If varname is empty
93     */
94    public String getVar(final String varname)
95     {
96      final String value = this.vars.get(varname);
97      return (value == null) ? "" : value; //$NON-NLS-1$
98     }
99  
100 
101   /**
102    * Set template variables value.
103    *
104    * @param varname Template variable name
105    * @param value Template variable value, could  be null
106    * @throws NullPointerException If varname is null
107    * @throws IllegalArgumentException If varname is empty
108    */
109   public void setVar(final String varname, final String value)
110    {
111     // if (!value.matches("^.+$"))
112     this.vars.put(varname, (value == null) ? "" : value); //$NON-NLS-1$
113    }
114 
115 
116   /**
117    * Unset template variable.
118    *
119    * @param varname Template variable name
120    * @throws NullPointerException If varname is null
121    * @throws IllegalArgumentException If varname is empty
122    */
123   @SuppressWarnings("java:S1120")
124   public void unsetVar(final String varname)
125    {
126     /* String value = */ this.vars.remove(varname);
127    }
128 
129 
130   /**
131    * Get list with all undefined template variables.
132    *
133    * @param varname Variable to parse for undefined variables
134    * @return List with undefined template variables names
135    * @throws NullPointerException If varname is null
136    * @throws IllegalArgumentException If varname is empty
137    */
138   public List<String> getUndefined(final String varname)
139    {
140     // TODO asserts
141     final var matcher = VariableManager.BLOCK_MATCHER_REGEXP.matcher(getVar(varname));
142     boolean result = matcher.find();
143     final List<String> undefvars = new ArrayList<>();
144     while (result)
145      {
146       final String vname = matcher.group(1);
147       if (!this.vars.containsKey(vname) && !undefvars.contains(vname))
148        {
149         undefvars.add(vname);
150        }
151       result = matcher.find();
152      }
153     return Collections.unmodifiableList(undefvars);
154    }
155 
156 
157   /* *
158    * Replace variables old version.
159    *
160    * @param block Template block
161    * @return Template/Block with replaced variables
162    */
163   /*
164   private String replaceVarsOld(String block)
165    {
166     assert (block != null) && !block.isEmpty();
167     // loop over all known variables an replace them
168     if (!this.vars.isEmpty())
169      {
170       final Set<Entry<String, String>> tempVarsSet = this.vars.entrySet();
171       for (Entry<String, String> mapEntry : tempVarsSet)
172        {
173         // convert into regexp (special char filter)
174         block = Pattern.compile("\\{" + mapEntry.getKey() + "\\}").matcher(block).replaceAll(mapEntry.getValue()); //$NON-NLS-1$ //$NON-NLS-2$
175        }
176      }
177     return block;
178    }
179   */
180 
181 
182   /**
183    * Replace variables new version.
184    *
185    * @param block Template block
186    * @return Template/Block with replaced variables
187    */
188   private String replaceVarsNew(final String block)
189    {
190     // assert (block != null) && !block.isEmpty();
191     // assert block.matches("^.+$")
192     // Get variable names to replace from varname
193     final var matcherTemplate = VariableManager.TEMPLATE_MATCHER_REGEXP.matcher(block);
194     final Set<String> varsSetTemplate = new TreeSet<>();
195     while (matcherTemplate.find())
196      {
197       final var varnameTemplate = block.substring(matcherTemplate.start() + 1, matcherTemplate.end() - 1);
198       if (this.vars.containsKey(varnameTemplate))
199        {
200         varsSetTemplate.add(varnameTemplate);
201        }
202      }
203     String resBlock = block;
204     for (final String varName : varsSetTemplate)
205      {
206       resBlock = resBlock.replaceAll("\\{" + varName + "\\}", getVar(varName)); //$NON-NLS-1$ //$NON-NLS-2$
207      }
208     return resBlock;
209    }
210 
211 
212   /**
213    * Substitute variable with its content.
214    *
215    * @param varname Variable name
216    * @return Replaced variable content or empty string
217    * @throws NullPointerException If varname is null
218    * @throws IllegalArgumentException If varname is empty
219    */
220   public String subst(final String varname)
221    {
222     // return replaceVarsOld(getVar(varname));
223     return replaceVarsNew(getVar(varname));
224    }
225 
226 
227   /**
228    * Parse a variable and replace all variables within it by their content.
229    *
230    * @param target Target for parsing operation
231    * @param varname Parse the content of this variable
232    * @param append true for appending blocks to target, otherwise false for replacing targets content
233    * @return Variables content after parsing
234    * @throws NullPointerException If target or varname is null
235    * @throws IllegalArgumentException If target or varname is empty
236    */
237   @SuppressWarnings("java:S2301")
238   public String parse(final String target, final String varname, final boolean append)
239    {
240     LOGGER.debug("varname: {}", varname);
241     final String str = subst(varname);
242     LOGGER.debug("str: {}", str);
243     setVar(target, (append ? getVar(target) : "") + str); //$NON-NLS-1$
244     return str;
245    }
246 
247 
248   /**
249    * Get list of all template variables.
250    *
251    * @return Array with names of template variables
252    */
253   public List<String> getVars()
254    {
255     if (this.vars.isEmpty())
256      {
257       return Collections.emptyList();
258      }
259     final List<String> result = new ArrayList<>(this.vars.size());
260     for (final Entry<String, String> entry : this.vars.entrySet())
261      {
262       result.add(entry.getKey()); // entry.getValue();
263      }
264     return Collections.unmodifiableList(result);
265    }
266 
267 
268   /**
269    * Returns the string representation of this  VariableManager.
270    *
271    * The exact details of this representation are unspecified and subject to change, but the following may be regarded as typical:
272    *
273    * " VariableManager[vars=[name, ...]]"
274    *
275    * @return String representation of this  VariableManager.
276    * @see java.lang.Object#toString()
277    */
278   @Override
279   public String toString()
280    {
281     return new StringBuilder().append("VariableManager[vars=").append(getVars()).append(']').toString(); //$NON-NLS-1$
282    }
283 
284 
285   /**
286    * Calculate hash code.
287    *
288    * @return Hash
289    * @see java.lang.Object#hashCode()
290    */
291   @Override
292   public int hashCode()
293    {
294     return Objects.hash(this.vars);
295    }
296 
297 
298   /**
299    * Is equal with another object.
300    *
301    * @param obj Object
302    * @return true when equal, false otherwise
303    * @see java.lang.Object#equals(java.lang.Object)
304    */
305   @Override
306   public boolean equals(final Object obj)
307    {
308     if (this == obj)
309      {
310       return true;
311      }
312     if (!(obj instanceof VariableManager))
313      {
314       return false;
315      }
316     final VariableManager other = (VariableManager)obj;
317     return this.vars.equals(other.vars);
318    }
319 
320  }