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.reflect.Array; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Collection; 024import java.util.List; 025 026import org.apache.logging.log4j.core.LogEvent; 027import org.apache.logging.log4j.core.config.Configuration; 028import org.apache.logging.log4j.core.config.Node; 029import org.apache.logging.log4j.core.config.plugins.PluginElement; 030import org.apache.logging.log4j.core.config.plugins.util.PluginType; 031 032/** 033 * PluginVisitor implementation for {@link PluginElement}. Supports arrays as well as singular values. 034 */ 035public class PluginElementVisitor extends AbstractPluginVisitor<PluginElement> { 036 public PluginElementVisitor() { 037 super(PluginElement.class); 038 } 039 040 @Override 041 public Object visit(final Configuration configuration, final Node node, final LogEvent event, 042 final StringBuilder log) { 043 final String name = this.annotation.value(); 044 if (this.conversionType.isArray()) { 045 setConversionType(this.conversionType.getComponentType()); 046 final List<Object> values = new ArrayList<>(); 047 final Collection<Node> used = new ArrayList<>(); 048 log.append("={"); 049 boolean first = true; 050 for (final Node child : node.getChildren()) { 051 final PluginType<?> childType = child.getType(); 052 if (name.equalsIgnoreCase(childType.getElementName()) || 053 this.conversionType.isAssignableFrom(childType.getPluginClass())) { 054 if (!first) { 055 log.append(", "); 056 } 057 first = false; 058 used.add(child); 059 final Object childObject = child.getObject(); 060 if (childObject == null) { 061 LOGGER.error("Null object returned for {} in {}.", child.getName(), node.getName()); 062 continue; 063 } 064 if (childObject.getClass().isArray()) { 065 log.append(Arrays.toString((Object[]) childObject)).append('}'); 066 node.getChildren().removeAll(used); 067 return childObject; 068 } 069 log.append(child.toString()); 070 values.add(childObject); 071 } 072 } 073 log.append('}'); 074 // note that we need to return an empty array instead of null if the types are correct 075 if (!values.isEmpty() && !this.conversionType.isAssignableFrom(values.get(0).getClass())) { 076 LOGGER.error("Attempted to assign attribute {} to list of type {} which is incompatible with {}.", 077 name, values.get(0).getClass(), this.conversionType); 078 return null; 079 } 080 node.getChildren().removeAll(used); 081 // we need to use reflection here because values.toArray() will cause type errors at runtime 082 final Object[] array = (Object[]) Array.newInstance(this.conversionType, values.size()); 083 for (int i = 0; i < array.length; i++) { 084 array[i] = values.get(i); 085 } 086 return array; 087 } 088 final Node namedNode = findNamedNode(name, node.getChildren()); 089 if (namedNode == null) { 090 log.append(name).append("=null"); 091 return null; 092 } 093 log.append(namedNode.getName()).append('(').append(namedNode.toString()).append(')'); 094 node.getChildren().remove(namedNode); 095 return namedNode.getObject(); 096 } 097 098 private Node findNamedNode(final String name, final Iterable<Node> children) { 099 for (final Node child : children) { 100 final PluginType<?> childType = child.getType(); 101 if (childType == null) { 102 //System.out.println(); 103 } 104 if (name.equalsIgnoreCase(childType.getElementName()) || 105 this.conversionType.isAssignableFrom(childType.getPluginClass())) { 106 // FIXME: check child.getObject() for null? 107 // doing so would be more consistent with the array version 108 return child; 109 } 110 } 111 return null; 112 } 113}