LCOV - code coverage report
Current view: top level - common/data - ParameterizedString.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 96 101 95.0 %
Date: 2022-11-19 15:00:39 Functions: 24 26 92.3 %

          Line data    Source code
       1             : // Copyright (C) 2009 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.common.data;
      16             : 
      17             : import java.util.ArrayList;
      18             : import java.util.Arrays;
      19             : import java.util.Collections;
      20             : import java.util.HashMap;
      21             : import java.util.List;
      22             : import java.util.Map;
      23             : 
      24             : /** Performs replacements on strings such as <code>Hello ${user}</code>. */
      25             : public class ParameterizedString {
      26             :   /** Obtain a string which has no parameters and always produces the value. */
      27             :   public static ParameterizedString asis(String constant) {
      28           1 :     return new ParameterizedString(new Constant(constant));
      29             :   }
      30             : 
      31             :   private final String pattern;
      32             :   private final String rawPattern;
      33             :   private final List<Format> patternOps;
      34             :   private final List<Parameter> parameters;
      35             : 
      36             :   protected ParameterizedString() {
      37           0 :     this(new Constant(""));
      38           0 :   }
      39             : 
      40           1 :   private ParameterizedString(Constant c) {
      41           1 :     pattern = c.text;
      42           1 :     rawPattern = c.text;
      43           1 :     patternOps = Collections.singletonList(c);
      44           1 :     parameters = Collections.emptyList();
      45           1 :   }
      46             : 
      47         147 :   public ParameterizedString(String pattern) {
      48         147 :     final StringBuilder raw = new StringBuilder();
      49         147 :     final List<Parameter> prs = new ArrayList<>(4);
      50         147 :     final List<Format> ops = new ArrayList<>(4);
      51             : 
      52         147 :     int i = 0;
      53         147 :     while (i < pattern.length()) {
      54         147 :       final int b = pattern.indexOf("${", i);
      55         147 :       if (b < 0) {
      56         147 :         break;
      57             :       }
      58         147 :       final int e = pattern.indexOf("}", b + 2);
      59         147 :       if (e < 0) {
      60           0 :         break;
      61             :       }
      62             : 
      63         147 :       raw.append(pattern, i, b);
      64         147 :       ops.add(new Constant(pattern.substring(i, b)));
      65             : 
      66             :       // "${parameter[.functions...]}" -> "parameter[.functions...]"
      67         147 :       final Parameter p = new Parameter(pattern.substring(b + 2, e));
      68             : 
      69         147 :       raw.append("{").append(prs.size()).append("}");
      70         147 :       prs.add(p);
      71         147 :       ops.add(p);
      72             : 
      73         147 :       i = e + 1;
      74         147 :     }
      75         147 :     if (i < pattern.length()) {
      76         147 :       raw.append(pattern.substring(i));
      77         147 :       ops.add(new Constant(pattern.substring(i)));
      78             :     }
      79             : 
      80         147 :     this.pattern = pattern;
      81         147 :     this.rawPattern = raw.toString();
      82         147 :     this.patternOps = Collections.unmodifiableList(ops);
      83         147 :     this.parameters = Collections.unmodifiableList(prs);
      84         147 :   }
      85             : 
      86             :   /** Get the original pattern given to the constructor. */
      87             :   public String getPattern() {
      88          48 :     return pattern;
      89             :   }
      90             : 
      91             :   /** Get the pattern with variables replaced with {0}, {1}, ... */
      92             :   public String getRawPattern() {
      93         107 :     return rawPattern;
      94             :   }
      95             : 
      96             :   /** Get the list of parameter names, ordered by appearance in the pattern. */
      97             :   public List<String> getParameterNames() {
      98         107 :     final ArrayList<String> r = new ArrayList<>(parameters.size());
      99         107 :     for (Parameter p : parameters) {
     100           2 :       r.add(p.name);
     101           2 :     }
     102         107 :     return Collections.unmodifiableList(r);
     103             :   }
     104             : 
     105             :   /** Convert a map of parameters into a value array for binding. */
     106             :   public String[] bind(Map<String, String> params) {
     107           1 :     final String[] r = new String[parameters.size()];
     108           1 :     for (int i = 0; i < r.length; i++) {
     109           1 :       final StringBuilder b = new StringBuilder();
     110           1 :       parameters.get(i).format(b, params);
     111           1 :       r[i] = b.toString();
     112             :     }
     113           1 :     return r;
     114             :   }
     115             : 
     116             :   /** Format this string by performing the variable replacements. */
     117             :   public String replace(Map<String, String> params) {
     118         113 :     final StringBuilder r = new StringBuilder();
     119         113 :     for (Format f : patternOps) {
     120         113 :       f.format(r, params);
     121         113 :     }
     122         113 :     return r.toString();
     123             :   }
     124             : 
     125             :   public Builder replace(String name, String value) {
     126         103 :     return new Builder().replace(name, value);
     127             :   }
     128             : 
     129             :   @Override
     130             :   public String toString() {
     131           0 :     return getPattern();
     132             :   }
     133             : 
     134         103 :   public final class Builder {
     135         103 :     private final Map<String, String> params = new HashMap<>();
     136             : 
     137             :     public Builder replace(String name, String value) {
     138         103 :       params.put(name, value);
     139         103 :       return this;
     140             :     }
     141             : 
     142             :     @Override
     143             :     public String toString() {
     144         103 :       return ParameterizedString.this.replace(params);
     145             :     }
     146             :   }
     147             : 
     148             :   private abstract static class Format {
     149             :     abstract void format(StringBuilder b, Map<String, String> p);
     150             :   }
     151             : 
     152             :   private static class Constant extends Format {
     153             :     private final String text;
     154             : 
     155         147 :     Constant(String text) {
     156         147 :       this.text = text;
     157         147 :     }
     158             : 
     159             :     @Override
     160             :     void format(StringBuilder b, Map<String, String> p) {
     161         113 :       b.append(text);
     162         113 :     }
     163             :   }
     164             : 
     165             :   private static class Parameter extends Format {
     166             :     private final String name;
     167             :     private final List<Function> functions;
     168             : 
     169         147 :     Parameter(String parameter) {
     170             :       // "parameter[.functions...]" -> (parameter, functions...)
     171         147 :       final List<String> names = Arrays.asList(parameter.split("\\."));
     172         147 :       final List<Function> functs = new ArrayList<>(names.size());
     173             : 
     174         147 :       if (names.isEmpty()) {
     175           0 :         name = "";
     176             :       } else {
     177         147 :         name = names.get(0);
     178             : 
     179         147 :         for (String fname : names.subList(1, names.size())) {
     180           1 :           final Function function = FUNCTIONS.get(fname);
     181           1 :           if (function != null) {
     182           1 :             functs.add(function);
     183             :           }
     184           1 :         }
     185             :       }
     186             : 
     187         147 :       functions = Collections.unmodifiableList(functs);
     188         147 :     }
     189             : 
     190             :     @Override
     191             :     void format(StringBuilder b, Map<String, String> p) {
     192         111 :       String v = p.get(name);
     193         111 :       if (v == null) {
     194           1 :         v = "";
     195             :       }
     196         111 :       for (Function function : functions) {
     197           1 :         v = function.apply(v);
     198           1 :       }
     199         111 :       b.append(v);
     200         111 :     }
     201             :   }
     202             : 
     203             :   private abstract static class Function {
     204             :     abstract String apply(String a);
     205             :   }
     206             : 
     207         147 :   private static final Map<String, Function> FUNCTIONS = initFunctions();
     208             : 
     209             :   private static Map<String, Function> initFunctions() {
     210         147 :     HashMap<String, Function> m = new HashMap<>();
     211         147 :     m.put(
     212             :         "toLowerCase",
     213         147 :         new Function() {
     214             :           @Override
     215             :           String apply(String a) {
     216           1 :             return a.toLowerCase();
     217             :           }
     218             :         });
     219         147 :     m.put(
     220             :         "toUpperCase",
     221         147 :         new Function() {
     222             :           @Override
     223             :           String apply(String a) {
     224           1 :             return a.toUpperCase();
     225             :           }
     226             :         });
     227         147 :     m.put(
     228             :         "localPart",
     229         147 :         new Function() {
     230             :           @Override
     231             :           String apply(String a) {
     232           1 :             int at = a.indexOf('@');
     233           1 :             return at < 0 ? a : a.substring(0, at);
     234             :           }
     235             :         });
     236         147 :     return Collections.unmodifiableMap(m);
     237             :   }
     238             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750