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
028    package ch.qos.logback.tyler.base;
029
030    import ch.qos.logback.classic.Level;
031    import ch.qos.logback.classic.LoggerContext;
032    import ch.qos.logback.classic.spi.Configurator;
033    import ch.qos.logback.classic.tyler.TylerConfiguratorBase;
034    import ch.qos.logback.core.Context;
035    import ch.qos.logback.core.model.processor.ModelInterpretationContext;
036    import ch.qos.logback.tyler.base.spi.StaticImportData;
037    import com.squareup.javapoet.FieldSpec;
038    import com.squareup.javapoet.MethodSpec;
039    import com.squareup.javapoet.ParameterSpec;
040    import com.squareup.javapoet.TypeSpec;
041
042    import javax.lang.model.element.Modifier;
043
044    import java.util.*;
045
046    import static ch.qos.logback.tyler.base.TylerConstants.CONFIGURE_METHOD_NAME;
047    import static ch.qos.logback.tyler.base.TylerConstants.CONTEXT_FIELD_NAME;
048    import static ch.qos.logback.tyler.base.TylerConstants.LEVEL_FIELD_NAME;
049    import static ch.qos.logback.tyler.base.TylerConstants.LOGGER_CONTEXT_PARAMETER_NAME;
050    import static ch.qos.logback.tyler.base.TylerConstants.REQUIRED_LOGBACK_VERSION;
051    import static ch.qos.logback.tyler.base.TylerConstants.TYLER_VERSION;
052
053    public class TylerModelInterpretationContext extends ModelInterpretationContext {
054
055        final public TypeSpec.Builder tylerConfiguratorTSB;
056        final public MethodSpec.Builder configureMethodSpecBuilder;
057        final public Map<String, MethodSpec.Builder> mapOfMethodSpecBuilders = new LinkedHashMap<>();
058
059        final FieldSpec contextFieldSpec = FieldSpec.builder(LoggerContext.class, CONTEXT_FIELD_NAME, Modifier.PRIVATE).build();
060        final ParameterSpec contextParameterSpec = ParameterSpec.builder(LoggerContext.class, LOGGER_CONTEXT_PARAMETER_NAME).build();
061        final ParameterSpec levelParameterSpec = ParameterSpec.builder(Level.class, LEVEL_FIELD_NAME).build();
062
063        final List<StaticImportData> staticImportsList = new ArrayList<>();
064
065        public TylerModelInterpretationContext(Context context) {
066            super(context);
067            this.configureMethodSpecBuilder = initializeConfigureMethodSpecBuilder();
068            this.tylerConfiguratorTSB = initializeTylerConfiguratorTSB();
069        }
070
071        public void addStaticImport(StaticImportData sid) {
072            if (!staticImportsList.contains(sid))
073                staticImportsList.add(sid);
074        }
075
076        TypeSpec.Builder initializeTylerConfiguratorTSB() {
077            //MethodSpec setupLoggerMS = makeSetupLoggerMethodSpec();
078
079            TypeSpec.Builder tsb = TypeSpec.classBuilder(TylerConstants.TYLER_CONFIGURATOR).addJavadoc("""
080                                            
081                                            <p>This file was generated by logback-tyler version %s</p>
082                                            
083                                            <p>Eventual errors and warnings are appended at the end.</p>                    
084                                            
085                                            <p>You may experiment with logback.xml to Java translation, i.e. 
086                                            TylerConfigurator generation, at the following URL:</p>
087                                            
088                                            <p>     https://logback.qos.ch/translator/services/xml2Java.html </p>
089                                            
090                                            <p>This generated TylerConfigurator class is intended to be copied and integrated 
091                                            into the user's project as a custom configurator. It will configure logback 
092                                            without XML. You are free to rename TylerConfigurator as you wish.</p>
093                                            
094                                            <p>It requires logback-classic version %s or later at runtime.</p>
095                                            
096                                            <p>Custom configurators are looked up via Java's service-provide facility. If a 
097                                            custom provider is found, it takes precedence over logback's own configurators, 
098                                            e.g. DefaultJoranConfigurator.</p>
099                                            
100                                            <p>To install your custom configurator to your project, add a 
101                                            provider-configuration file to the following path:</p> 
102                                            
103                                            <pre>  META-INF/services/ch.qos.logback.classic.spi.Configurator</pre>
104                                            
105                                            <p>This provider-configuration file should contain a line with the fully 
106                                            qualified class name of your tyler configurator.</p>
107                                            
108                                            <p>See also item 1 of 'Configuration at initialization' section at </p>
109                                            
110                                            <p>  https://logback.qos.ch/manual/configuration.html#auto_configuration</p> 
111                                            
112                                            <p>With recent versions of logback and logback-tyler you can still
113                                            configure logger levels dynamically using properties files. Note that
114                                            configuration files in properties format can be watched for
115                                            changes. See the documentation on PropertiesConfigurator for more details.</p>
116                                            
117                                            <p>https://logback.qos.ch/manual/configuration.html#propertiesConfigurator</p>
118                                            
119                                            <p>Keep in mind that by integrating a .properties configuration file info 
120                                            your tyler configurator, you can still change logger levels dynamically, without 
121                                            redeploying your application.</p>
122                                            
123                                            """.formatted(TYLER_VERSION, REQUIRED_LOGBACK_VERSION))
124                            .addSuperinterface(Configurator.class)
125                            .superclass(TylerConfiguratorBase.class)
126                            .addModifiers(Modifier.PUBLIC);
127            return tsb;
128        }
129
130        private MethodSpec.Builder initializeConfigureMethodSpecBuilder() {
131            MethodSpec.Builder msb = MethodSpec.methodBuilder(CONFIGURE_METHOD_NAME).addJavadoc("""
132                                            <p>This method performs configuration per {@link $T} interface.</p>
133                                            
134                                            <p>If <code>TylerConfigurator</code> is installed as a configurator service, this 
135                                            method will be called by logback-classic during initialization.</p>
136                                            """, Configurator.class).addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).addParameter(contextParameterSpec)
137                            .returns(Configurator.ExecutionStatus.class)
138                            .addStatement("$N($N)", TylerConfiguratorBase.SET_CONTEXT_METHOD_NAME, contextParameterSpec);
139
140            return msb;
141        }
142
143        public FieldSpec getContextFieldSpec() {
144            return contextFieldSpec;
145        }
146    }