001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.util; 018 019import java.io.Serializable; 020import java.util.ArrayList; 021import java.util.List; 022import java.util.Map; 023import java.util.Objects; 024import java.util.concurrent.ConcurrentHashMap; 025import java.util.regex.Matcher; 026import java.util.regex.Pattern; 027 028/** 029 * A source for global configuration properties. 030 * 031 * @since 2.10.0 032 */ 033public interface PropertySource { 034 035 /** 036 * Returns the order in which this PropertySource has priority. A higher value means that the source will be 037 * applied later so as to take precedence over other property sources. 038 * 039 * @return priority value 040 */ 041 int getPriority(); 042 043 /** 044 * Iterates over all properties and performs an action for each key/value pair. 045 * 046 * @param action action to perform on each key/value pair 047 */ 048 default void forEach(BiConsumer<String, String> action) { 049 } 050 051 /** 052 * Converts a list of property name tokens into a normal form. For example, a list of tokens such as 053 * "foo", "bar", "baz", might be normalized into the property name "log4j2.fooBarBaz". 054 * 055 * @param tokens list of property name tokens 056 * @return a normalized property name using the given tokens 057 */ 058 default CharSequence getNormalForm(Iterable<? extends CharSequence> tokens) { 059 return null; 060 } 061 062 /** 063 * For PropertySources that cannot iterate over all the potential properties this provides a direct lookup. 064 * @param key The key to search for. 065 * @return The value or null; 066 * @since 2.13.0 067 */ 068 default String getProperty(String key) { 069 return null; 070 } 071 072 073 /** 074 * For PropertySources that cannot iterate over all the potential properties this provides a direct lookup. 075 * @param key The key to search for. 076 * @return The value or null; 077 * @since 2.13.0 078 */ 079 default boolean containsProperty(String key) { 080 return false; 081 } 082 083 /** 084 * Comparator for ordering PropertySource instances by priority. 085 * 086 * @since 2.10.0 087 */ 088 class Comparator implements java.util.Comparator<PropertySource>, Serializable { 089 private static final long serialVersionUID = 1L; 090 091 @Override 092 public int compare(final PropertySource o1, final PropertySource o2) { 093 return Integer.compare(Objects.requireNonNull(o1).getPriority(), Objects.requireNonNull(o2).getPriority()); 094 } 095 } 096 097 /** 098 * Utility methods useful for PropertySource implementations. 099 * 100 * @since 2.10.0 101 */ 102 final class Util { 103 private static final String PREFIXES = "(?i:^log4j2?[-._/]?|^org\\.apache\\.logging\\.log4j\\.)?"; 104 private static final Pattern PROPERTY_TOKENIZER = Pattern.compile(PREFIXES + "([A-Z]*[a-z0-9]+|[A-Z0-9]+)[-._/]?"); 105 private static final Map<CharSequence, List<CharSequence>> CACHE = new ConcurrentHashMap<>(); 106 107 /** 108 * Converts a property name string into a list of tokens. This will strip a prefix of {@code log4j}, 109 * {@code log4j2}, {@code Log4j}, or {@code org.apache.logging.log4j}, along with separators of 110 * dash {@code -}, dot {@code .}, underscore {@code _}, and slash {@code /}. Tokens can also be separated 111 * by camel case conventions without needing a separator character in between. 112 * 113 * @param value property name 114 * @return the property broken into lower case tokens 115 */ 116 public static List<CharSequence> tokenize(final CharSequence value) { 117 if (CACHE.containsKey(value)) { 118 return CACHE.get(value); 119 } 120 final List<CharSequence> tokens = new ArrayList<>(); 121 final Matcher matcher = PROPERTY_TOKENIZER.matcher(value); 122 while (matcher.find()) { 123 tokens.add(matcher.group(1).toLowerCase()); 124 } 125 CACHE.put(value, tokens); 126 return tokens; 127 } 128 129 /** 130 * Joins a list of strings using camelCaseConventions. 131 * 132 * @param tokens tokens to convert 133 * @return tokensAsCamelCase 134 */ 135 public static CharSequence joinAsCamelCase(final Iterable<? extends CharSequence> tokens) { 136 final StringBuilder sb = new StringBuilder(); 137 boolean first = true; 138 for (final CharSequence token : tokens) { 139 if (first) { 140 sb.append(token); 141 } else { 142 sb.append(Character.toUpperCase(token.charAt(0))); 143 if (token.length() > 1) { 144 sb.append(token.subSequence(1, token.length())); 145 } 146 } 147 first = false; 148 } 149 return sb.toString(); 150 } 151 152 private Util() { 153 } 154 } 155}