001/* 002 * Copyright (c) 2024 QOS.ch Sarl (Switzerland) 003 * All rights reserved. 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining 006 * a copy of this software and associated documentation files (the 007 * "Software"), to deal in the Software without restriction, including 008 * without limitation the rights to use, copy, modify, merge, publish, 009 * distribute, sublicense, and/or sell copies of the Software, and to 010 * permit persons to whom the Software is furnished to do so, subject to 011 * the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be 014 * included in all copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 023 * 024 * 025 * 026 */ 027 028package ch.qos.logback.tyler.base.handler; 029 030import ch.qos.logback.core.Context; 031import ch.qos.logback.core.model.ComponentModel; 032import ch.qos.logback.core.model.Model; 033import ch.qos.logback.core.model.processor.ModelHandlerBase; 034import ch.qos.logback.core.model.processor.ModelHandlerException; 035import ch.qos.logback.core.model.processor.ModelInterpretationContext; 036import ch.qos.logback.core.spi.LifeCycle; 037import ch.qos.logback.core.util.OptionHelper; 038import ch.qos.logback.tyler.base.TylerModelInterpretationContext; 039import ch.qos.logback.tyler.base.util.ClassUtil; 040import ch.qos.logback.tyler.base.util.VariableNameUtil; 041import com.squareup.javapoet.ClassName; 042import com.squareup.javapoet.MethodSpec; 043 044import static ch.qos.logback.tyler.base.TylerConstants.SETUP; 045 046public abstract class ComponentModelHandler extends ModelHandlerBase { 047 048 private boolean inError; 049 ImplicitModelHandlerData implicitModelHandlerData; 050 051 public ComponentModelHandler(Context context) { 052 super(context); 053 } 054 055 abstract String getTargetType(); 056 057 @Override 058 public void handle(ModelInterpretationContext mic, Model model) throws ModelHandlerException { 059 060 ComponentModel componentModel = (ComponentModel) model; 061 TylerModelInterpretationContext tmic = (TylerModelInterpretationContext) mic; 062 063 String componentClassName = componentModel.getClassName(); 064 if (OptionHelper.isNullOrEmptyOrAllSpaces(componentClassName)) { 065 addWarn("Missing className. This should have been caught earlier."); 066 inError = true; 067 return; 068 } else { 069 componentClassName = mic.getImport(componentClassName); 070 } 071 072 addInfo("About to configure " + getTargetType() + " of type [" + componentClassName + "]"); 073 MethodSpec.Builder methodSpec = addJavaStatement(tmic, componentClassName); 074 addAdditionalJavaStatement(methodSpec, componentModel); 075 this.implicitModelHandlerData = ImplicitModelHandlerData.makeInstance(this, methodSpec, componentClassName); 076 if(implicitModelHandlerData != null) { 077 mic.pushObject(implicitModelHandlerData); 078 } else { 079 addError("Could not make implicitModelHandlerData for ["+componentClassName+"]"); 080 model.markAsSkipped(); 081 inError = true; 082 } 083 } 084 085 protected void addAdditionalJavaStatement(MethodSpec.Builder methodSpec, ComponentModel componentModel) { 086 087 } 088 089 MethodSpec.Builder addJavaStatement(TylerModelInterpretationContext tmic, 090 String componentClassName) { 091 092 093 String simpleName = ClassUtil.extractSimpleClassName(componentClassName); 094 095 ClassName desiredComponentCN = ClassName.get(ClassUtil.extractPackageName(componentClassName), 096 simpleName); 097 098 String variableName = VariableNameUtil.fullyQualifiedClassNameToVariableName(componentClassName); 099 100 MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder( 101 SETUP + simpleName).returns(void.class) 102 .addStatement("$1T $2N = new $1T()", desiredComponentCN, variableName) 103 .addStatement("$N.setContext($N)", variableName, tmic.getContextFieldSpec()); 104 105 return methodSpecBuilder; 106 } 107 108 @Override 109 public void postHandle(ModelInterpretationContext mic, Model model) { 110 if (inError) { 111 return; 112 } 113 114 Object o = mic.peekObject(); 115 if (o != implicitModelHandlerData) { 116 addWarn("The object at the of the stack is not the implicitModelHandlerData pushed earlier."); 117 } else { 118 TylerModelInterpretationContext tmic = (TylerModelInterpretationContext) mic; 119 tmic.popObject(); 120 121 MethodSpec.Builder componentMethodBuilder = implicitModelHandlerData.methodSpecBuilder; 122 123 String variableName = implicitModelHandlerData.getVariableName(); 124 125 componentMethodBuilder.addCode("\n"); 126 componentMethodBuilder.beginControlFlow("if($N instanceof $T)", variableName, LifeCycle.class); 127 componentMethodBuilder.addStatement("(($T)$N).start()", LifeCycle.class, variableName); 128 componentMethodBuilder.endControlFlow(); 129 MethodSpec statusListenerMethodSpec = componentMethodBuilder.build(); 130 131 tmic.tylerConfiguratorTSB.addMethod(statusListenerMethodSpec); 132 133 tmic.configureMethodSpecBuilder.addStatement("$N()", statusListenerMethodSpec); 134 } 135 136 } 137}