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