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 */ 027package ch.qos.logback.tyler.base; 028 029import ch.qos.logback.classic.joran.JoranConfigurator; 030import ch.qos.logback.classic.model.ConfigurationModel; 031import ch.qos.logback.classic.model.ContextNameModel; 032import ch.qos.logback.classic.model.LevelModel; 033import ch.qos.logback.classic.model.LoggerContextListenerModel; 034import ch.qos.logback.classic.model.LoggerModel; 035import ch.qos.logback.classic.model.RootLoggerModel; 036import ch.qos.logback.classic.model.processor.LogbackClassicDefaultNestedComponentRules; 037import ch.qos.logback.core.Context; 038import ch.qos.logback.core.joran.event.SaxEventRecorder; 039import ch.qos.logback.core.joran.spi.JoranException; 040import ch.qos.logback.core.model.AppenderModel; 041import ch.qos.logback.core.model.AppenderRefModel; 042import ch.qos.logback.core.model.DefineModel; 043import ch.qos.logback.core.model.ImplicitModel; 044import ch.qos.logback.core.model.ImportModel; 045import ch.qos.logback.core.model.Model; 046import ch.qos.logback.core.model.PropertyModel; 047import ch.qos.logback.core.model.SequenceNumberGeneratorModel; 048import ch.qos.logback.core.model.ShutdownHookModel; 049import ch.qos.logback.core.model.StatusListenerModel; 050import ch.qos.logback.core.model.TimestampModel; 051import ch.qos.logback.core.model.conditional.ElseModel; 052import ch.qos.logback.core.model.conditional.IfModel; 053import ch.qos.logback.core.model.conditional.ThenModel; 054import ch.qos.logback.core.model.processor.DefaultProcessor; 055import ch.qos.logback.core.model.processor.ImportModelHandler; 056import ch.qos.logback.core.util.StatusPrinter2; 057import ch.qos.logback.tyler.base.handler.AppenderModelHandler; 058import ch.qos.logback.tyler.base.handler.AppenderRefModelHandler; 059import ch.qos.logback.tyler.base.handler.ConfigurationModelHandler; 060import ch.qos.logback.tyler.base.handler.ContextNameModelHandler; 061import ch.qos.logback.tyler.base.handler.DefineModelHandler; 062import ch.qos.logback.tyler.base.handler.ElseModelHandler; 063import ch.qos.logback.tyler.base.handler.IfModelHandler; 064import ch.qos.logback.tyler.base.handler.ThenModelHandler; 065import ch.qos.logback.tyler.base.handler.ImplicitModelHandler; 066import ch.qos.logback.tyler.base.handler.LevelModelHandler; 067import ch.qos.logback.tyler.base.handler.LoggerContextListenerModelHandler; 068import ch.qos.logback.tyler.base.handler.LoggerModelHandler; 069import ch.qos.logback.tyler.base.handler.RootLoggerModelHandler; 070import ch.qos.logback.tyler.base.handler.SequenceNumberGeneratorModelHandler; 071import ch.qos.logback.tyler.base.handler.ShutdownHookModelHandler; 072import ch.qos.logback.tyler.base.handler.StatusListenerModelHandler; 073import ch.qos.logback.tyler.base.handler.TimestampModelHandler; 074import ch.qos.logback.tyler.base.handler.VariableModelHandler; 075import ch.qos.logback.tyler.base.util.StringPrintStream; 076import com.squareup.javapoet.JavaFile; 077import com.squareup.javapoet.MethodSpec; 078import com.squareup.javapoet.TypeSpec; 079import org.xml.sax.InputSource; 080 081import java.io.ByteArrayInputStream; 082import java.io.IOException; 083import java.io.InputStream; 084import java.util.ArrayList; 085import java.util.Arrays; 086import java.util.List; 087 088public class ModelToJava { 089 090 091 final Context context; 092 093 public ModelToJava(Context context) { 094 this.context = context; 095 } 096 097 098 public Model extractModel(String input) throws JoranException { 099 InputStream inputStream = new ByteArrayInputStream(input.getBytes()); 100 InputSource inputSource = new InputSource(inputStream); 101 inputSource.setSystemId("UNKNOWN"); 102 103 JoranConfigurator joranConfigurator = new JoranConfigurator(); 104 joranConfigurator.setContext(context); 105 106 SaxEventRecorder recorder = joranConfigurator.populateSaxEventRecorder(inputSource); 107 Model top = joranConfigurator.buildModelFromSaxEventList(recorder.getSaxEventList()); 108 return top; 109 } 110 111 public StringBuffer toJavaAsStringBuffer(Model topModel) throws IOException { 112 TylerModelInterpretationContext tmic = new TylerModelInterpretationContext(context); 113 tmic.setTopModel(topModel); 114 115 LogbackClassicDefaultNestedComponentRules.addDefaultNestedComponentRegistryRules(tmic.getDefaultNestedComponentRegistry()); 116 117 DefaultProcessor defaultProcessor = new DefaultProcessor(context, tmic); 118 addModelHandlerAssociations(defaultProcessor); 119 120 defaultProcessor.process(topModel); 121 122 123 tmic.configureMethodSpecBuilder.addStatement("return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY"); 124 MethodSpec configureMethodSpec = tmic.configureMethodSpecBuilder.build(); 125 126 tmic.tylerConfiguratorTSB.methodSpecs.addFirst(configureMethodSpec); 127 128 129 TypeSpec tylerConfiguratorTypeSpec = tmic.tylerConfiguratorTSB.build(); 130 131 JavaFile.Builder javaFileBuilder = JavaFile.builder("com.example", tylerConfiguratorTypeSpec); 132 133 tmic.staticImportsList.forEach(sid -> javaFileBuilder.addStaticImport(sid.aClass(), sid.methodName())); 134 135 JavaFile javaFile = javaFileBuilder.indent(" ").build(); 136 137 StringBuffer sb = new StringBuffer(); 138 139 javaFile.writeTo(sb); 140 return sb; 141 } 142 143 public String toJava(Model topModel) throws IOException { 144 StringBuffer buf = toJavaAsStringBuffer(topModel); 145 return buf.toString(); 146 } 147 148 public List<String> statusToStringList() { 149 List<String> resultList = new ArrayList<>(); 150 StatusPrinter2 statusPrinter2 = new StatusPrinter2(); 151 StringPrintStream sps = new StringPrintStream(System.out, false); 152 statusPrinter2.setPrintStream(sps); 153 statusPrinter2.print(context); 154 for(String s: sps.stringList) { 155 String[] split = s.split("\n"); 156 Arrays.stream(split).forEach(n -> resultList.add("// "+n)); 157 } 158 return resultList; 159 } 160 161 private void addModelHandlerAssociations(DefaultProcessor defaultProcessor) { 162 defaultProcessor.addHandler(ConfigurationModel.class, ConfigurationModelHandler::makeInstance); 163 164 defaultProcessor.addHandler(PropertyModel.class, VariableModelHandler::makeInstance); 165 166 167 defaultProcessor.addHandler(ContextNameModel.class, ContextNameModelHandler::makeInstance); 168 defaultProcessor.addHandler(ImportModel.class, ImportModelHandler::makeInstance); 169 defaultProcessor.addHandler(DefineModel.class, DefineModelHandler::makeInstance); 170 defaultProcessor.addHandler(StatusListenerModel.class, StatusListenerModelHandler::makeInstance); 171 defaultProcessor.addHandler(ShutdownHookModel.class, ShutdownHookModelHandler::makeInstance); 172 defaultProcessor.addHandler(TimestampModel.class, TimestampModelHandler::makeInstance); 173 174 defaultProcessor.addHandler(AppenderModel.class, AppenderModelHandler::makeInstance); 175 defaultProcessor.addHandler(ImplicitModel.class, ImplicitModelHandler::makeInstance); 176 defaultProcessor.addHandler(LoggerModel.class, LoggerModelHandler::makeInstance); 177 defaultProcessor.addHandler(RootLoggerModel.class, RootLoggerModelHandler::makeInstance); 178 defaultProcessor.addHandler(LevelModel.class, LevelModelHandler::makeInstance); 179 defaultProcessor.addHandler(AppenderRefModel.class, AppenderRefModelHandler::makeInstance); 180 181 defaultProcessor.addHandler(LoggerContextListenerModel.class, LoggerContextListenerModelHandler::makeInstance); 182 defaultProcessor.addHandler(SequenceNumberGeneratorModel.class, SequenceNumberGeneratorModelHandler::makeInstance); 183 184 185 defaultProcessor.addHandler(IfModel.class, IfModelHandler::makeInstance); 186 defaultProcessor.addHandler(ThenModel.class, ThenModelHandler::makeInstance); 187 defaultProcessor.addHandler(ElseModel.class, ElseModelHandler::makeInstance); 188 189 } 190 191}