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}