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 */
017
018package org.apache.logging.log4j.core.config.plugins.visitors;
019
020import java.lang.annotation.Annotation;
021import java.lang.reflect.Member;
022import java.util.Map;
023
024import org.apache.logging.log4j.Logger;
025import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
026import org.apache.logging.log4j.core.lookup.StrSubstitutor;
027import org.apache.logging.log4j.core.util.Assert;
028import org.apache.logging.log4j.status.StatusLogger;
029import org.apache.logging.log4j.util.Strings;
030
031/**
032 * Base class for PluginVisitor implementations. Provides convenience methods as well as all method implementations
033 * other than the {@code visit} method.
034 *
035 * @param <A> the Plugin annotation type.
036 */
037public abstract class AbstractPluginVisitor<A extends Annotation> implements PluginVisitor<A> {
038
039    protected static final Logger LOGGER = StatusLogger.getLogger();
040
041    protected final Class<A> clazz;
042    protected A annotation;
043    protected String[] aliases;
044    protected Class<?> conversionType;
045    protected StrSubstitutor substitutor;
046    protected Member member;
047
048    /**
049     * This constructor must be overridden by implementation classes as a no-arg constructor.
050     *
051     * @param clazz the annotation class this PluginVisitor is for.
052     */
053    protected AbstractPluginVisitor(final Class<A> clazz) {
054        this.clazz = clazz;
055    }
056
057    @SuppressWarnings("unchecked")
058    @Override
059    public PluginVisitor<A> setAnnotation(final Annotation annotation) {
060        final Annotation a = Assert.requireNonNull(annotation, "No annotation was provided");
061        if (this.clazz.isInstance(a)) {
062            this.annotation = (A) a;
063        }
064        return this;
065    }
066
067    @Override
068    public PluginVisitor<A> setAliases(final String... aliases) {
069        this.aliases = aliases;
070        return this;
071    }
072
073    @Override
074    public PluginVisitor<A> setConversionType(final Class<?> conversionType) {
075        this.conversionType = Assert.requireNonNull(conversionType, "No conversion type class was provided");
076        return this;
077    }
078
079    @Override
080    public PluginVisitor<A> setStrSubstitutor(final StrSubstitutor substitutor) {
081        this.substitutor = Assert.requireNonNull(substitutor, "No StrSubstitutor was provided");
082        return this;
083    }
084
085    @Override
086    public PluginVisitor<A> setMember(final Member member) {
087        this.member = member;
088        return this;
089    }
090
091    /**
092     * Removes an Entry from a given Map using a key name and aliases for that key. Keys are case-insensitive.
093     *
094     * @param attributes the Map to remove an Entry from.
095     * @param name       the key name to look up.
096     * @param aliases    optional aliases of the key name to look up.
097     * @return the value corresponding to the given key or {@code null} if nonexistent.
098     */
099    protected static String removeAttributeValue(final Map<String, String> attributes,
100                                                 final String name,
101                                                 final String... aliases) {
102        for (final Map.Entry<String, String> entry : attributes.entrySet()) {
103            final String key = entry.getKey();
104            final String value = entry.getValue();
105            if (key.equalsIgnoreCase(name)) {
106                attributes.remove(key);
107                return value;
108            }
109            if (aliases != null) {
110                for (final String alias : aliases) {
111                    if (key.equalsIgnoreCase(alias)) {
112                        attributes.remove(key);
113                        return value;
114                    }
115                }
116            }
117        }
118        return null;
119    }
120
121    /**
122     * Converts the given value into the configured type falling back to the provided default value.
123     *
124     * @param value        the value to convert.
125     * @param defaultValue the fallback value to use in case of no value or an error.
126     * @return the converted value whether that be based on the given value or the default value.
127     */
128    protected Object convert(final String value, final Object defaultValue) {
129        if (defaultValue instanceof String) {
130            return TypeConverters.convert(value, this.conversionType, Strings.trimToNull((String) defaultValue));
131        }
132        return TypeConverters.convert(value, this.conversionType, defaultValue);
133    }
134}