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 void forEach(BiConsumer<String, String> action); 049 050 /** 051 * Converts a list of property name tokens into a normal form. For example, a list of tokens such as 052 * "foo", "bar", "baz", might be normalized into the property name "log4j2.fooBarBaz". 053 * 054 * @param tokens list of property name tokens 055 * @return a normalized property name using the given tokens 056 */ 057 CharSequence getNormalForm(Iterable<? extends CharSequence> tokens); 058 059 /** 060 * Comparator for ordering PropertySource instances by priority. 061 * 062 * @since 2.10.0 063 */ 064 class Comparator implements java.util.Comparator<PropertySource>, Serializable { 065 private static final long serialVersionUID = 1L; 066 067 @Override 068 public int compare(final PropertySource o1, final PropertySource o2) { 069 return Integer.compare(Objects.requireNonNull(o1).getPriority(), Objects.requireNonNull(o2).getPriority()); 070 } 071 } 072 073 /** 074 * Utility methods useful for PropertySource implementations. 075 * 076 * @since 2.10.0 077 */ 078 final class Util { 079 private static final String PREFIXES = "(?i:^log4j2?[-._/]?|^org\\.apache\\.logging\\.log4j\\.)?"; 080 private static final Pattern PROPERTY_TOKENIZER = Pattern.compile(PREFIXES + "([A-Z]*[a-z0-9]+|[A-Z0-9]+)[-._/]?"); 081 private static final Map<CharSequence, List<CharSequence>> CACHE = new ConcurrentHashMap<>(); 082 083 /** 084 * Converts a property name string into a list of tokens. This will strip a prefix of {@code log4j}, 085 * {@code log4j2}, {@code Log4j}, or {@code org.apache.logging.log4j}, along with separators of 086 * dash {@code -}, dot {@code .}, underscore {@code _}, and slash {@code /}. Tokens can also be separated 087 * by camel case conventions without needing a separator character in between. 088 * 089 * @param value property name 090 * @return the property broken into lower case tokens 091 */ 092 public static List<CharSequence> tokenize(final CharSequence value) { 093 if (CACHE.containsKey(value)) { 094 return CACHE.get(value); 095 } 096 final List<CharSequence> tokens = new ArrayList<>(); 097 final Matcher matcher = PROPERTY_TOKENIZER.matcher(value); 098 while (matcher.find()) { 099 tokens.add(matcher.group(1).toLowerCase()); 100 } 101 CACHE.put(value, tokens); 102 return tokens; 103 } 104 105 /** 106 * Joins a list of strings using camelCaseConventions. 107 * 108 * @param tokens tokens to convert 109 * @return tokensAsCamelCase 110 */ 111 public static CharSequence joinAsCamelCase(final Iterable<? extends CharSequence> tokens) { 112 final StringBuilder sb = new StringBuilder(); 113 boolean first = true; 114 for (final CharSequence token : tokens) { 115 if (first) { 116 sb.append(token); 117 } else { 118 sb.append(Character.toUpperCase(token.charAt(0))); 119 if (token.length() > 1) { 120 sb.append(token.subSequence(1, token.length())); 121 } 122 } 123 first = false; 124 } 125 return sb.toString(); 126 } 127 128 private Util() { 129 } 130 } 131}