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    
018    package org.apache.logging.log4j.core.config.plugins.visitors;
019    
020    import java.lang.annotation.Annotation;
021    import java.lang.reflect.Member;
022    import java.util.Map;
023    
024    import org.apache.logging.log4j.Logger;
025    import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
026    import org.apache.logging.log4j.core.lookup.StrSubstitutor;
027    import org.apache.logging.log4j.core.util.Assert;
028    import org.apache.logging.log4j.status.StatusLogger;
029    import 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     */
037    public 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    }