ch.qos.logback.classic.gaffer.ComponentDelegate.groovy Maven / Gradle / Ivy
/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2015, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.classic.gaffer
import ch.qos.logback.core.spi.ContextAwareBase
import ch.qos.logback.core.spi.LifeCycle
import ch.qos.logback.core.spi.ContextAware
import ch.qos.logback.core.joran.spi.NoAutoStartUtil
/**
* @author Ceki Gücü
*/
class ComponentDelegate extends ContextAwareBase {
final Object component;
final List fieldsToCascade = [];
ComponentDelegate(Object component) {
this.component = component;
}
String getLabel() { "component" }
String getLabelFistLetterInUpperCase() { getLabel()[0].toUpperCase() + getLabel().substring(1) }
void methodMissing(String name, def args) {
NestingType nestingType = PropertyUtil.nestingType(component, name, null);
if (nestingType == NestingType.NA) {
addError("${getLabelFistLetterInUpperCase()} ${getComponentName()} of type [${component.getClass().canonicalName}] has no appplicable [${name}] property.")
return;
}
String subComponentName
Class clazz
Closure closure
(subComponentName, clazz, closure) = analyzeArgs(args)
if (clazz != null) {
Object subComponent = clazz.newInstance()
if (subComponentName && subComponent.hasProperty(name)) {
subComponent.name = subComponentName;
}
if (subComponent instanceof ContextAware) {
subComponent.context = context;
}
if (closure) {
ComponentDelegate subDelegate = new ComponentDelegate(subComponent)
cascadeFields(subDelegate)
subDelegate.context = context
injectParent(subComponent)
closure.delegate = subDelegate
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure()
}
if (subComponent instanceof LifeCycle && NoAutoStartUtil.notMarkedWithNoAutoStart(subComponent)) {
subComponent.start();
}
PropertyUtil.attach(nestingType, component, subComponent, name)
} else {
addError("No 'class' argument specified for [${name}] in ${getLabel()} ${getComponentName()} of type [${component.getClass().canonicalName}]");
}
}
void cascadeFields(ComponentDelegate subDelegate) {
for (String k: fieldsToCascade) {
subDelegate.metaClass."${k}" = this."${k}"
}
}
void injectParent(Object subComponent) {
if(subComponent.hasProperty("parent")) {
subComponent.parent = component;
}
}
void propertyMissing(String name, def value) {
NestingType nestingType = PropertyUtil.nestingType(component, name, value);
if (nestingType == NestingType.NA) {
addError("${getLabelFistLetterInUpperCase()} ${getComponentName()} of type [${component.getClass().canonicalName}] has no appplicable [${name}] property ")
return;
}
PropertyUtil.attach(nestingType, component, value, name)
}
def analyzeArgs(Object[] args) {
String name;
Class clazz;
Closure closure;
if (args.size() > 3) {
addError("At most 3 arguments allowed but you passed $args")
return [name, clazz, closure]
}
if (args[-1] instanceof Closure) {
closure = args[-1]
args -= args[-1]
}
if (args.size() == 1) {
clazz = parseClassArgument(args[0])
}
if (args.size() == 2) {
name = parseNameArgument(args[0])
clazz = parseClassArgument(args[1])
}
return [name, clazz, closure]
}
Class parseClassArgument(arg) {
if (arg instanceof Class) {
return arg
} else if (arg instanceof String) {
return Class.forName(arg)
} else {
addError("Unexpected argument type ${arg.getClass().canonicalName}")
return null;
}
}
String parseNameArgument(arg) {
if (arg instanceof String) {
return arg
} else {
addError("With 2 or 3 arguments, the first argument must be the component name, i.e of type string")
return null;
}
}
String getComponentName() {
if (component.hasProperty("name"))
return "[${component.name}]"
else
return ""
}
}