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