001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2002, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.model.processor; 015 016import ch.qos.logback.core.Context; 017import ch.qos.logback.core.joran.action.ImcplicitActionDataForBasicProperty; 018import ch.qos.logback.core.joran.action.ImplicitModelData; 019import ch.qos.logback.core.joran.action.ImplicitModelDataForComplexProperty; 020import ch.qos.logback.core.joran.spi.NoAutoStartUtil; 021import ch.qos.logback.core.joran.util.PropertySetter; 022import ch.qos.logback.core.joran.util.beans.BeanDescriptionCache; 023import ch.qos.logback.core.model.ComponentModel; 024import ch.qos.logback.core.model.ImplicitModel; 025import ch.qos.logback.core.model.Model; 026import ch.qos.logback.core.spi.ContextAware; 027import ch.qos.logback.core.spi.LifeCycle; 028import ch.qos.logback.core.util.AggregationType; 029import ch.qos.logback.core.util.Loader; 030import ch.qos.logback.core.util.OptionHelper; 031 032public class ImplicitModelHandler extends ModelHandlerBase { 033 034 private final BeanDescriptionCache beanDescriptionCache; 035 private ImplicitModelData implicitModelData; 036 037 static final String PARENT_PROPPERTY_KEY = "parent"; 038 039 boolean inError = false; 040 041 public ImplicitModelHandler(Context context, BeanDescriptionCache beanDescriptionCache) { 042 super(context); 043 this.beanDescriptionCache = beanDescriptionCache; 044 } 045 046 protected Class<? extends ImplicitModel> getSupportedModelClass() { 047 return ImplicitModel.class; 048 } 049 050 static public ImplicitModelHandler makeInstance(Context context, ModelInterpretationContext mic) { 051 BeanDescriptionCache beanDescriptionCache = mic.getBeanDescriptionCache(); 052 return new ImplicitModelHandler(context, beanDescriptionCache); 053 } 054 055 @Override 056 public void handle(ModelInterpretationContext mic, Model model) { 057 058 ImplicitModel implicitModel = (ImplicitModel) model; 059 060 // calling intercon.peekObject with an empty stack will throw an exception 061 if (mic.isObjectStackEmpty()) { 062 inError = true; 063 return; 064 } 065 String nestedElementTagName = implicitModel.getTag(); 066 067 Object o = mic.peekObject(); 068 PropertySetter parentBean = new PropertySetter(beanDescriptionCache, o); 069 parentBean.setContext(context); 070 071 AggregationType aggregationType = parentBean.computeAggregationType(nestedElementTagName); 072 073// Stack<ImplicitModelData> actionDataStack = mic.getImplicitModelDataStack(); 074 075 switch (aggregationType) { 076 case NOT_FOUND: 077 addWarn("Ignoring unkown property [" + nestedElementTagName + "] in [" + o.getClass().getName() + "]"); 078 inError = true; 079 // no point in processing submodels 080 implicitModel.markAsSkipped(); 081 return; 082 case AS_BASIC_PROPERTY: 083 case AS_BASIC_PROPERTY_COLLECTION: 084 ImcplicitActionDataForBasicProperty adBasicProperty = new ImcplicitActionDataForBasicProperty(parentBean, 085 aggregationType, nestedElementTagName); 086 implicitModelData = adBasicProperty; 087 doBasicProperty(mic, model, adBasicProperty); 088 return; 089 // we only push action data if NestComponentIA is applicable 090 case AS_COMPLEX_PROPERTY_COLLECTION: 091 case AS_COMPLEX_PROPERTY: 092 ImplicitModelDataForComplexProperty adComplex = new ImplicitModelDataForComplexProperty(parentBean, 093 aggregationType, nestedElementTagName); 094 implicitModelData = adComplex; 095 doComplex(mic, implicitModel, adComplex); 096 return; 097 default: 098 addError("PropertySetter.computeAggregationType returned " + aggregationType); 099 return; 100 } 101 102 } 103 104 void doBasicProperty(ModelInterpretationContext interpretationContext, Model model, 105 ImcplicitActionDataForBasicProperty actionData) { 106 String finalBody = interpretationContext.subst(model.getBodyText()); 107 // get the action data object pushed in isApplicable() method call 108 // IADataForBasicProperty actionData = (IADataForBasicProperty) 109 // actionDataStack.peek(); 110 switch (actionData.aggregationType) { 111 case AS_BASIC_PROPERTY: 112 actionData.parentBean.setProperty(actionData.propertyName, finalBody); 113 break; 114 case AS_BASIC_PROPERTY_COLLECTION: 115 actionData.parentBean.addBasicProperty(actionData.propertyName, finalBody); 116 break; 117 default: 118 addError("Unexpected aggregationType " + actionData.aggregationType); 119 } 120 } 121 122 public void doComplex(ModelInterpretationContext interpretationContext, ComponentModel componentModel, 123 ImplicitModelDataForComplexProperty actionData) { 124 125 String className = componentModel.getClassName(); 126 // perform variable name substitution 127 String substClassName = interpretationContext.subst(className); 128 129 String fqcn = interpretationContext.getImport(substClassName); 130 131 Class<?> componentClass = null; 132 try { 133 134 if (!OptionHelper.isNullOrEmpty(fqcn)) { 135 componentClass = Loader.loadClass(fqcn, context); 136 } else { 137 // guess class name via implicit rules 138 PropertySetter parentBean = actionData.parentBean; 139 componentClass = parentBean.getClassNameViaImplicitRules(actionData.propertyName, 140 actionData.getAggregationType(), interpretationContext.getDefaultNestedComponentRegistry()); 141 } 142 143 if (componentClass == null) { 144 actionData.inError = true; 145 String errMsg = "Could not find an appropriate class for property [" + componentModel.getTag() + "]"; 146 addError(errMsg); 147 return; 148 } 149 150 if (OptionHelper.isNullOrEmpty(fqcn)) { 151 addInfo("Assuming default type [" + componentClass.getName() + "] for [" + componentModel.getTag() 152 + "] property"); 153 } 154 155 actionData.setNestedComplexProperty(componentClass.getConstructor().newInstance()); 156 157 // pass along the repository 158 if (actionData.getNestedComplexProperty() instanceof ContextAware) { 159 ((ContextAware) actionData.getNestedComplexProperty()).setContext(this.context); 160 } 161 // addInfo("Pushing component [" + localName 162 // + "] on top of the object stack."); 163 interpretationContext.pushObject(actionData.getNestedComplexProperty()); 164 165 } catch (Exception oops) { 166 actionData.inError = true; 167 String msg = "Could not create component [" + componentModel.getTag() + "] of type [" + fqcn + "]"; 168 addError(msg, oops); 169 } 170 } 171 172 @Override 173 public void postHandle(ModelInterpretationContext intercon, Model model) { 174 if (inError) { 175 return; 176 } 177 178 if(implicitModelData == null) 179 return; 180 181 // the action data can in an incorrect state, in which case we need to 182 // disengage 183 if(implicitModelData.inError) { 184 return; 185 } 186 if (implicitModelData instanceof ImplicitModelDataForComplexProperty) { 187 postHandleComplex(intercon, model, (ImplicitModelDataForComplexProperty) implicitModelData); 188 } 189 190 } 191 192 private void postHandleComplex(ModelInterpretationContext mic, Model model, 193 ImplicitModelDataForComplexProperty imdComplex) { 194 195 PropertySetter nestedBean = new PropertySetter(beanDescriptionCache, 196 imdComplex.getNestedComplexProperty()); 197 nestedBean.setContext(context); 198 199 // have the nested element point to its parent if possible 200 if (nestedBean.computeAggregationType(PARENT_PROPPERTY_KEY) == AggregationType.AS_COMPLEX_PROPERTY) { 201 nestedBean.setComplexProperty(PARENT_PROPPERTY_KEY, imdComplex.parentBean.getObj()); 202 } 203 204 // start the nested complex property if it implements LifeCycle and is not 205 // marked with a @NoAutoStart annotation 206 Object nestedComplexProperty = imdComplex.getNestedComplexProperty(); 207 if (nestedComplexProperty instanceof LifeCycle 208 && NoAutoStartUtil.notMarkedWithNoAutoStart(nestedComplexProperty)) { 209 ((LifeCycle) nestedComplexProperty).start(); 210 } 211 212 Object o = mic.peekObject(); 213 214 if (o != imdComplex.getNestedComplexProperty()) { 215 addError("The object on the top the of the stack is not the component pushed earlier."); 216 } else { 217 mic.popObject(); 218 // Now let us attach the component 219 switch (imdComplex.aggregationType) { 220 case AS_COMPLEX_PROPERTY: 221 imdComplex.parentBean.setComplexProperty(model.getTag(), imdComplex.getNestedComplexProperty()); 222 223 break; 224 case AS_COMPLEX_PROPERTY_COLLECTION: 225 imdComplex.parentBean.addComplexProperty(model.getTag(), imdComplex.getNestedComplexProperty()); 226 break; 227 default: 228 addError("Unexpected aggregationType " + imdComplex.aggregationType); 229 } 230 } 231 } 232 233}