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.Model; 032import ch.qos.logback.core.model.conditional.IfModel; 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.util.OptionHelper; 037import ch.qos.logback.tyler.base.TylerModelInterpretationContext; 038 039/** 040 * Handler responsible for processing IfModel instances encountered during model interpretation. 041 * <p> 042 * This handler pushes the IfModel onto the interpretation stack, validates the condition 043 * string and emits the corresponding Java "if" control flow into the Tyler configuration 044 * method being built (via MethodSpec). 045 * </p> 046 */ 047public class IfModelHandler extends ModelHandlerBase { 048 049 /** 050 * Create a new IfModelHandler. 051 * 052 * @param context the Logback context used for this handler 053 */ 054 public IfModelHandler(Context context) { 055 super(context); 056 } 057 058 /** 059 * Factory method used by the model processing infrastructure. 060 * 061 * @param context the Logback context 062 * @param ic the current ModelInterpretationContext (unused by this factory) 063 * @return a new instance of IfModelHandler 064 */ 065 static public ModelHandlerBase makeInstance(Context context, ModelInterpretationContext ic) { 066 return new IfModelHandler(context); 067 } 068 069 /** 070 * Return the model class that this handler supports. 071 * 072 * @return the supported model class (IfModel.class) 073 */ 074 @Override 075 protected Class<IfModel> getSupportedModelClass() { 076 return IfModel.class; 077 } 078 079 /** 080 * Handle an {@link IfModel} by validating its condition and emitting the 081 * corresponding Java "if" statement into the Tyler method spec builder. 082 * 083 * @param mic the model interpretation context 084 * @param model the model to handle (expected to be {@link IfModel}) 085 * @throws ModelHandlerException if an error occurs while handling the model 086 */ 087 @Override 088 public void handle(ModelInterpretationContext mic, Model model) throws ModelHandlerException { 089 IfModel ifModel = (IfModel) model; 090 TylerModelInterpretationContext tmic = (TylerModelInterpretationContext) mic; 091 092 093 Object o = tmic.peekObject(); 094 String conditionStr = null; 095 096 if(o instanceof ConditionStringRecord conditionStringRecord) { 097 conditionStr = conditionStringRecord.value(); 098 mic.popObject(); 099 } 100 101 mic.pushModel(ifModel); 102 if(conditionStr == null) { 103 conditionStr = ifModel.getCondition(); 104 } 105 106 int lineNum = model.getLineNumber(); 107 108 if (!OptionHelper.isNullOrEmptyOrAllSpaces(conditionStr)) { 109 addJavaStatement(tmic, conditionStr); 110 } else { 111 addError("Empty condition for <if> element on line "+lineNum); 112 } 113 } 114 115 /** 116 * Emit the Java "if" control flow for the given condition into the supplied 117 * TylerModelInterpretationContext's MethodSpec builder. 118 * 119 * @param tmic the Tyler model interpretation context containing the MethodSpec builder 120 * @param conditionStr the Java expression to use as the if condition 121 */ 122 protected void addJavaStatement(TylerModelInterpretationContext tmic, String conditionStr) { 123 tmic.configureMethodSpecBuilder.beginControlFlow("if($N)", conditionStr); 124 } 125 126 /** 127 * Finalize handling of the {@link IfModel}: verify the model stack, end the 128 * emitted control flow and pop the model from the stack. 129 * 130 * @param mic the model interpretation context 131 * @param model the model that was handled 132 */ 133 @Override 134 public void postHandle(ModelInterpretationContext mic, Model model) { 135 if(mic.isModelStackEmpty()) { 136 addError("Unexpected unexpected empty model stack."); 137 return; 138 } 139 140 Object o = mic.peekModel(); 141 if (!(o instanceof IfModel)) { 142 addWarn("The object [" + o + "] on the top the of the stack is not of type [" + IfModel.class); 143 } else { 144 TylerModelInterpretationContext tmic = (TylerModelInterpretationContext) mic; 145 tmic.configureMethodSpecBuilder.endControlFlow(); 146 mic.popModel(); 147 } 148 149 } 150}