View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.logging.log4j.core.config.plugins.convert;
    19
    20  import java.io.File;
    21  import java.math.BigDecimal;
    22  import java.math.BigInteger;
    23  import java.net.MalformedURLException;
    24  import java.net.URI;
    25  import java.net.URISyntaxException;
    26  import java.net.URL;
    27  import java.nio.charset.Charset;
    28  import java.security.Provider;
    29  import java.security.Security;
    30  import java.util.regex.Pattern;
    31  import javax.xml.bind.DatatypeConverter;
    32
    33  import org.apache.logging.log4j.Level;
    34  import org.apache.logging.log4j.Logger;
    35  import org.apache.logging.log4j.core.config.plugins.Plugin;
    36  import org.apache.logging.log4j.core.util.Loader;
    37  import org.apache.logging.log4j.status.StatusLogger;
    38
    39  /**
    40   * Collection of basic TypeConverter implementations. May be used to register additional TypeConverters or find
    41   * registered TypeConverters.
    42   *
    43   * @since 2.1 Moved to the {@code convert} package.
    44   */
    45  public final class TypeConverters {
    46
    47      /**
    48       * The {@link Plugin#category() Plugin Category} to use for {@link TypeConverter} plugins.
    49       *
    50       * @since 2.1
    51       */
    52      public static final String CATEGORY = "TypeConverter";
    53
    54      /**
    55       * Parses a {@link String} into a {@link BigDecimal}.
    56       */
    57      @Plugin(name = "BigDecimal", category = CATEGORY)
    58      public static class BigDecimalConverter implements TypeConverter<BigDecimal> {
    59          @Override
    60          public BigDecimal convert(final String s) {
    61              return new BigDecimal(s);
    62          }
    63      }
    64
    65      /**
    66       * Parses a {@link String} into a {@link BigInteger}.
    67       */
    68      @Plugin(name = "BigInteger", category = CATEGORY)
    69      public static class BigIntegerConverter implements TypeConverter<BigInteger> {
    70          @Override
    71          public BigInteger convert(final String s) {
    72              return new BigInteger(s);
    73          }
    74      }
    75
    76      /**
    77       * Converts a {@link String} into a {@link Boolean}.
    78       */
    79      @Plugin(name = "Boolean", category = CATEGORY)
    80      public static class BooleanConverter implements TypeConverter<Boolean> {
    81          @Override
    82          public Boolean convert(final String s) {
    83              return Boolean.valueOf(s);
    84          }
    85      }
    86
    87      /**
    88       * Converts a {@link String} into a {@code byte[]}.
    89       *
    90       * The supported formats are:
    91       * <ul>
    92       * <li>0x0123456789ABCDEF</li>
    93       * <li>Base64:ABase64String</li>
    94       * <li>String</li>
    95       * </ul>
    96       */
    97      @Plugin(name = "ByteArray", category = CATEGORY)
    98      public static class ByteArrayConverter implements TypeConverter<byte[]> {
    99
    100         private static final String PREFIX_0x = "0x";
    101         private static final String PREFIX_BASE64 = "Base64:";
    102
    103         @Override
    104         public byte[] convert(final String value) {
    105             byte[] bytes;
    106             if (value == null || value.isEmpty()) {
    107                 bytes = new byte[0];
    108             } else if (value.startsWith(PREFIX_BASE64)) {
    109                 final String lexicalXSDBase64Binary = value.substring(PREFIX_BASE64.length());
    110                 bytes = DatatypeConverter.parseBase64Binary(lexicalXSDBase64Binary);
    111             } else if (value.startsWith(PREFIX_0x)) {
    112                 final String lexicalXSDHexBinary = value.substring(PREFIX_0x.length());
    113                 bytes = DatatypeConverter.parseHexBinary(lexicalXSDHexBinary);
    114             } else {
    115                 bytes = value.getBytes(Charset.defaultCharset());
    116             }
    117             return bytes;
    118         }
    119     }
    120
    121     /**
    122      * Converts a {@link String} into a {@link Byte}.
    123      */
    124     @Plugin(name = "Byte", category = CATEGORY)
    125     public static class ByteConverter implements TypeConverter<Byte> {
    126         @Override
    127         public Byte convert(final String s) {
    128             return Byte.valueOf(s);
    129         }
    130     }
    131
    132     /**
    133      * Converts a {@link String} into a {@link Character}.
    134      */
    135     @Plugin(name = "Character", category = CATEGORY)
    136     public static class CharacterConverter implements TypeConverter<Character> {
    137         @Override
    138         public Character convert(final String s) {
    139             if (s.length() != 1) {
    140                 throw new IllegalArgumentException("Character string must be of length 1: " + s);
    141             }
    142             return Character.valueOf(s.toCharArray()[0]);
    143         }
    144     }
    145
    146     /**
    147      * Converts a {@link String} into a {@code char[]}.
    148      */
    149     @Plugin(name = "CharacterArray", category = CATEGORY)
    150     public static class CharArrayConverter implements TypeConverter<char[]> {
    151         @Override
    152         public char[] convert(final String s) {
    153             return s.toCharArray();
    154         }
    155     }
    156
    157     /**
    158      * Converts a {@link String} into a {@link Charset}.
    159      */
    160     @Plugin(name = "Charset", category = CATEGORY)
    161     public static class CharsetConverter implements TypeConverter<Charset> {
    162         @Override
    163         public Charset convert(final String s) {
    164             return Charset.forName(s);
    165         }
    166     }
    167
    168     /**
    169      * Converts a {@link String} into a {@link Class}.
    170      */
    171     @Plugin(name = "Class", category = CATEGORY)
    172     public static class ClassConverter implements TypeConverter<Class<?>> {
    173         @Override
    174         public Class<?> convert(final String s) throws ClassNotFoundException {
    175             return Loader.loadClass(s);
    176         }
    177     }
    178
    179     /**
    180      * Converts a {@link String} into a {@link Double}.
    181      */
    182     @Plugin(name = "Double", category = CATEGORY)
    183     public static class DoubleConverter implements TypeConverter<Double> {
    184         @Override
    185         public Double convert(final String s) {
    186             return Double.valueOf(s);
    187         }
    188     }
    189
    190     /**
    191      * Converts a {@link String} into a {@link File}.
    192      */
    193     @Plugin(name = "File", category = CATEGORY)
    194     public static class FileConverter implements TypeConverter<File> {
    195         @Override
    196         public File convert(final String s) {
    197             return new File(s);
    198         }
    199     }
    200
    201     /**
    202      * Converts a {@link String} into a {@link Float}.
    203      */
    204     @Plugin(name = "Float", category = CATEGORY)
    205     public static class FloatConverter implements TypeConverter<Float> {
    206         @Override
    207         public Float convert(final String s) {
    208             return Float.valueOf(s);
    209         }
    210     }
    211
    212     /**
    213      * Converts a {@link String} into a {@link Integer}.
    214      */
    215     @Plugin(name = "Integer", category = CATEGORY)
    216     public static class IntegerConverter implements TypeConverter<Integer> {
    217         @Override
    218         public Integer convert(final String s) {
    219             return Integer.valueOf(s);
    220         }
    221     }
    222
    223     /**
    224      * Converts a {@link String} into a Log4j {@link Level}. Returns {@code null} for invalid level names.
    225      */
    226     @Plugin(name = "Level", category = CATEGORY)
    227     public static class LevelConverter implements TypeConverter<Level> {
    228         @Override
    229         public Level convert(final String s) {
    230             return Level.valueOf(s);
    231         }
    232     }
    233
    234     /**
    235      * Converts a {@link String} into a {@link Long}.
    236      */
    237     @Plugin(name = "Long", category = CATEGORY)
    238     public static class LongConverter implements TypeConverter<Long> {
    239         @Override
    240         public Long convert(final String s) {
    241             return Long.valueOf(s);
    242         }
    243     }
    244
    245     /**
    246      * Converts a {@link String} into a {@link Pattern}.
    247      */
    248     @Plugin(name = "Pattern", category = CATEGORY)
    249     public static class PatternConverter implements TypeConverter<Pattern> {
    250         @Override
    251         public Pattern convert(final String s) {
    252             return Pattern.compile(s);
    253         }
    254     }
    255
    256     /**
    257      * Converts a {@link String} into a {@link Provider}.
    258      */
    259     @Plugin(name = "SecurityProvider", category = CATEGORY)
    260     public static class SecurityProviderConverter implements TypeConverter<Provider> {
    261         @Override
    262         public Provider convert(final String s) {
    263             return Security.getProvider(s);
    264         }
    265     }
    266
    267     /**
    268      * Converts a {@link String} into a {@link Short}.
    269      */
    270     @Plugin(name = "Short", category = CATEGORY)
    271     public static class ShortConverter implements TypeConverter<Short> {
    272         @Override
    273         public Short convert(final String s) {
    274             return Short.valueOf(s);
    275         }
    276     }
    277
    278     /**
    279      * Returns the given {@link String}, no conversion takes place.
    280      */
    281     @Plugin(name = "String", category = CATEGORY)
    282     public static class StringConverter implements TypeConverter<String> {
    283         @Override
    284         public String convert(final String s) {
    285             return s;
    286         }
    287     }
    288
    289     /**
    290      * Converts a {@link String} into a {@link URI}.
    291      */
    292     @Plugin(name = "URI", category = CATEGORY)
    293     public static class UriConverter implements TypeConverter<URI> {
    294         @Override
    295         public URI convert(final String s) throws URISyntaxException {
    296             return new URI(s);
    297         }
    298     }
    299
    300     /**
    301      * Converts a {@link String} into a {@link URL}.
    302      */
    303     @Plugin(name = "URL", category = CATEGORY)
    304     public static class UrlConverter implements TypeConverter<URL> {
    305         @Override
    306         public URL convert(final String s) throws MalformedURLException {
    307             return new URL(s);
    308         }
    309     }
    310
    311     /**
    312      * Converts a String to a given class if a TypeConverter is available for that class. Falls back to the provided
    313      * default value if the conversion is unsuccessful. However, if the default value is <em>also</em> invalid, then
    314      * {@code null} is returned (along with a nasty status log message).
    315      *
    316      * @param s
    317      *        the string to convert
    318      * @param clazz
    319      *        the class to try to convert the string to
    320      * @param defaultValue
    321      *        the fallback object to use if the conversion is unsuccessful
    322      * @return the converted object which may be {@code null} if the string is invalid for the given type
    323      * @throws NullPointerException
    324      *         if {@code clazz} is {@code null}
    325      * @throws IllegalArgumentException
    326      *         if no TypeConverter exists for the given class
    327      */
    328     public static Object convert(final String s, final Class<?> clazz, final Object defaultValue) {
    329         final TypeConverter<?> converter = TypeConverterRegistry.getInstance().findCompatibleConverter(clazz);
    330         if (s == null) {
    331             // don't debug print here, resulting output is hard to understand
    332             // LOGGER.debug("Null string given to convert. Using default [{}].", defaultValue);
    333             return parseDefaultValue(converter, defaultValue);
    334         }
    335         try {
    336             return converter.convert(s);
    337         } catch (final Exception e) {
    338             LOGGER.warn("Error while converting string [{}] to type [{}]. Using default value [{}].", s, clazz,
    339                     defaultValue, e);
    340             return parseDefaultValue(converter, defaultValue);
    341         }
    342     }
    343
    344     private static Object parseDefaultValue(final TypeConverter<?> converter, final Object defaultValue) {
    345         if (defaultValue == null) {
    346             return null;
    347         }
    348         if (!(defaultValue instanceof String)) {
    349             return defaultValue;
    350         }
    351         try {
    352             return converter.convert((String) defaultValue);
    353         } catch (final Exception e) {
    354             LOGGER.debug("Can't parse default value [{}] for type [{}].", defaultValue, converter.getClass(), e);
    355             return null;
    356         }
    357     }
    358
    359     private static final Logger LOGGER = StatusLogger.getLogger();
    360
    361 }