1717 */
1818package org .apache .flume .node ;
1919
20+ import java .io .FileInputStream ;
21+ import java .io .IOException ;
22+ import java .io .InputStream ;
23+ import java .util .Arrays ;
2024import java .util .HashMap ;
25+ import java .util .Locale ;
2126import java .util .Map ;
27+ import java .util .Objects ;
2228import java .util .Properties ;
2329
2430import org .apache .commons .text .StringSubstitutor ;
31+ import org .apache .commons .text .lookup .DefaultStringLookup ;
2532import org .apache .commons .text .lookup .StringLookup ;
2633import org .apache .commons .text .lookup .StringLookupFactory ;
34+ import org .slf4j .Logger ;
35+ import org .slf4j .LoggerFactory ;
2736
2837/**
2938 * Resolves replaceable tokens to create a Map.
3241 */
3342final class MapResolver {
3443
44+ private static final Logger LOGGER = LoggerFactory .getLogger (MapResolver .class );
45+ private static final String DEFAULT_LOOKUPS = "lookups.properties" ;
46+ private static final String CUSTOM_LOOKUPS_KEY = "lookups" ;
3547 private static final String PROPS_IMPL_KEY = "propertiesImplementation" ;
3648 private static final String ENV_VAR_PROPERTY = "org.apache.flume.node.EnvVarResolverProperties" ;
49+ private static final String LOOKUP = "org.apache.commons.text.lookup.DefaultStringLookup." ;
50+ private static final LookupEntry [] LOOKUP_ENTRIES = {
51+ new LookupEntry ("sys" , DefaultStringLookup .SYSTEM_PROPERTIES .getStringLookup ()),
52+ new LookupEntry ("env" , DefaultStringLookup .ENVIRONMENT .getStringLookup ()) ,
53+ new LookupEntry ("java" , DefaultStringLookup .JAVA .getStringLookup ()),
54+ new LookupEntry ("date" , DefaultStringLookup .DATE .getStringLookup ())
55+ };
3756
3857 public static Map <String , String > resolveProperties (Properties properties ) {
3958 Map <String , String > map = new HashMap <>();
4059 boolean useEnvVars = ENV_VAR_PROPERTY .equals (System .getProperty (PROPS_IMPL_KEY ));
4160 StringLookup defaultLookup = useEnvVars ? new DefaultLookup (map ) :
4261 StringLookupFactory .INSTANCE .mapStringLookup (map );
43- StringLookup lookup = StringLookupFactory .INSTANCE .interpolatorStringLookup (defaultLookup );
62+ StringLookup lookup = StringLookupFactory .INSTANCE .interpolatorStringLookup (createLookupMap (),
63+ defaultLookup , false );
4464 StringSubstitutor substitutor = new StringSubstitutor (lookup );
4565 substitutor .setEnableSubstitutionInVariables (true );
4666 properties .stringPropertyNames ().forEach ((k ) -> map .put (k ,
4767 substitutor .replace (properties .getProperty (k ))));
4868 return map ;
4969 }
5070
71+ private static Map <String , StringLookup > createLookupMap () {
72+ Map <String , StringLookup > map = new HashMap <>();
73+ Properties properties = loadProperties ();
74+ if (properties == null ) {
75+ Arrays .stream (LOOKUP_ENTRIES ).forEach ((e ) -> {
76+ map .put (e .key , e .lookup );
77+ });
78+ } else {
79+ properties .forEach ((k , v ) -> {
80+ String key = Objects .toString (k );
81+ String value = Objects .toString (v );
82+ if (value .startsWith (LOOKUP )) {
83+ String lookupEnum = value .substring (LOOKUP .length ());
84+ try {
85+ StringLookup stringLookup = DefaultStringLookup .valueOf (lookupEnum ).getStringLookup ();
86+ map .put (key .toLowerCase (Locale .ROOT ), stringLookup );
87+ } catch (IllegalArgumentException ex ) {
88+ LOGGER .warn ("{} is not a DefaultStringLookup enum value, ignoring" , key );
89+ }
90+ } else {
91+ try {
92+ Class <?> clazz = Class .forName (Objects .toString (v ));
93+ if (StringLookup .class .isAssignableFrom (clazz )) {
94+ StringLookup stringLookup = (StringLookup ) clazz .newInstance ();
95+ map .put (k .toString ().toLowerCase (Locale .ROOT ), stringLookup );
96+ } else {
97+ LOGGER .warn ("{} is not a StringLookup, ignoring" , v );
98+ }
99+ } catch (Exception ex ) {
100+ LOGGER .warn ("Unable to load {} due to {}, ignoring" , v , ex .getMessage ());
101+ }
102+ }
103+ });
104+ }
105+ return map ;
106+ }
107+
51108 private static class DefaultLookup implements StringLookup {
52109 private final Map <String , String > properties ;
53110
@@ -67,4 +124,42 @@ public String lookup(String key) {
67124 properties .get (key ) : System .getenv (key );
68125 }
69126 }
127+
128+ private static class LookupEntry {
129+ private final String key ;
130+ private final StringLookup lookup ;
131+
132+ public LookupEntry (String key , StringLookup lookup ) {
133+ this .key = key ;
134+ this .lookup = lookup ;
135+ }
136+ }
137+
138+ private static Properties loadProperties () {
139+ final Properties properties = new Properties ();
140+ String fileName = System .getProperty (CUSTOM_LOOKUPS_KEY );
141+ if (fileName != null ) {
142+ try (InputStream inputStream = new FileInputStream (fileName )) {
143+ properties .load (inputStream );
144+ } catch (final IOException e ) {
145+ try (InputStream inputStream = ClassLoader .getSystemResourceAsStream (fileName )) {
146+ properties .load (inputStream );
147+ } catch (final IOException ex ) {
148+ LOGGER .warn ("Unable to load {} due to {}" , fileName , ex .getMessage ());
149+ }
150+ }
151+ }
152+ if (properties .size () == 0 ) {
153+ try (InputStream inputStream = ClassLoader .getSystemResourceAsStream (DEFAULT_LOOKUPS )) {
154+ if (inputStream != null ) {
155+ properties .load (inputStream );
156+ } else {
157+ return null ;
158+ }
159+ } catch (final IOException e ) {
160+ return null ;
161+ }
162+ }
163+ return properties ;
164+ }
70165}
0 commit comments