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.classic.util.ContextInitializer;
035    import ch.qos.logback.core.Context;
036    import ch.qos.logback.core.model.processor.ModelInterpretationContext;
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 static ch.qos.logback.tyler.base.TylerConstants.CONFIGURE_METHOD_NAME;
045    import static ch.qos.logback.tyler.base.TylerConstants.CONTEXT_FIELD_NAME;
046    import static ch.qos.logback.tyler.base.TylerConstants.LEVEL_FIELD_NAME;
047    import static ch.qos.logback.tyler.base.TylerConstants.LOGGER_CONTEXT_PARAMETER_NAME;
048    import static ch.qos.logback.tyler.base.TylerConstants.REQUIRED_LOGBACK_VERSION;
049
050    public class TylerModelInterpretationContext extends ModelInterpretationContext {
051
052
053        final public TypeSpec.Builder tylerConfiguratorTSB;
054        final public MethodSpec.Builder configureMethodSpecBuilder;
055
056
057        final FieldSpec contextFieldSpec = FieldSpec.builder(LoggerContext.class, CONTEXT_FIELD_NAME, Modifier.PRIVATE).build();
058        final ParameterSpec contextParameterSpec = ParameterSpec.builder(LoggerContext.class, LOGGER_CONTEXT_PARAMETER_NAME).build();
059        final ParameterSpec levelParameterSpec = ParameterSpec.builder(Level.class, LEVEL_FIELD_NAME).build();
060
061        public TylerModelInterpretationContext(Context context) {
062            super(context);
063            this.configureMethodSpecBuilder = initializeConfigureMethodSpecBuilder();
064            this.tylerConfiguratorTSB = initializeTylerConfiguratorTSB();
065        }
066
067
068        TypeSpec.Builder initializeTylerConfiguratorTSB() {
069            //MethodSpec setupLoggerMS = makeSetupLoggerMethodSpec();
070
071            TypeSpec.Builder tsb  = TypeSpec.classBuilder(TylerConstants.TYLER_CONFIGURATOR)
072                    .addJavadoc("""
073                     <p>BEWARE: As of March 2024, TylerConfigurator generation from logback.xml configuration files is 
074                    still experimental and incomplete.
075                    <p>
076                    
077                    <p>This class, i.e. TylerConfigurator, is intended to be copied and integrated into the user's 
078                    project as custom configurator. It will configure logback without XML.</p>
079                    
080                    <p>It requires logback-classic version %s or later at runtime.</p>
081                    
082                    <p>Custom configurators are looked up via Java's service-provide facility. If a custom provider is 
083                    found, it takes precedence over logback's own configurators, e.g. DefaultJoranConfigurator.</p>
084                    
085                    <p>See also item 1 of 'Configuration at initialization' section at 
086                    "https://logback.qos.ch/manual/configuration.html#auto_configuration </p>
087                    """.formatted(REQUIRED_LOGBACK_VERSION))
088                    .addSuperinterface(Configurator.class)
089                    .superclass(TylerConfiguratorBase.class);
090            return tsb;
091        }
092
093        private MethodSpec.Builder initializeConfigureMethodSpecBuilder() {
094            MethodSpec.Builder msb = MethodSpec.methodBuilder(CONFIGURE_METHOD_NAME)
095                    .addJavadoc("""
096                    <p>This method performs configuration per {@link $T} interface.</p>
097                    
098                    <p>If <code>TylerConfgiurator</code> is installed as a configurator service, this method will be 
099                    called by logback-classic during initialization.</p>
100                    """, Configurator.class)
101                    .addAnnotation(Override.class)
102                    .addModifiers(Modifier.PUBLIC)
103                    .addParameter(contextParameterSpec)
104                    .returns(Configurator.ExecutionStatus.class)
105                    .addStatement("$N($N)", TylerConfiguratorBase.SET_CONTEXT_METHOD_NAME, contextParameterSpec);
106
107            return msb;
108        }
109
110//        private MethodSpec makeSetupLoggerMethodSpec() {
111//            MethodSpec.Builder msb = MethodSpec.methodBuilder(SETUP_LOGGER_METHOD_NAME)
112//                    .addModifiers(Modifier.PRIVATE)
113//                    .addParameter(String.class, LOGGER_NAME_FIELD_NAME)
114//                    .addParameter(levelParameterSpec)
115//                    .addParameter(String.class, LEVEL_STRING_PARAMETER_NAME)
116//                    .addParameter(Boolean.class, ADDITIVITY_FIELD_NAME)
117//                    .returns(Logger.class)
118//                    .addStatement("$1T loggerContext = ($1T) $2N", LoggerContext.class, CONTEXT_FIELD_NAME)
119//                    .addStatement("$T $N = loggerContext.getLogger($N)", Logger.class, LOGGER_FIELD_NAME, LOGGER_NAME_FIELD_NAME)
120//                    .beginControlFlow("if (!$T.isNullOrEmptyOrAllSpaces($N))", OptionHelper.class, LEVEL_STRING_PARAMETER_NAME)
121//                    .addStatement("$N.setLevel($N)", LOGGER_FIELD_NAME, LEVEL_FIELD_NAME)
122//                    .endControlFlow()
123//                    .beginControlFlow("if ($N != null)", ADDITIVITY_FIELD_NAME)
124//                    .addStatement("$N.setAdditive($N)", LOGGER_FIELD_NAME, ADDITIVITY_FIELD_NAME)
125//                    .endControlFlow()
126//                    .addStatement("return $N", LOGGER_FIELD_NAME);
127//
128//            return msb.build();
129//        }
130
131        public FieldSpec getContextFieldSpec() {
132            return contextFieldSpec;
133        }
134    }