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