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
028package ch.qos.logback.tyler.base.handler;
029
030import ch.qos.logback.core.Context;
031import ch.qos.logback.core.joran.action.Action;
032import ch.qos.logback.core.joran.action.ActionUtil;
033import ch.qos.logback.core.joran.action.TimestampAction;
034import ch.qos.logback.core.model.Model;
035import ch.qos.logback.core.model.TimestampModel;
036import ch.qos.logback.core.model.processor.ModelHandlerBase;
037import ch.qos.logback.core.model.processor.ModelHandlerException;
038import ch.qos.logback.core.model.processor.ModelInterpretationContext;
039import ch.qos.logback.core.util.CachingDateFormatter;
040import ch.qos.logback.core.util.OptionHelper;
041import ch.qos.logback.tyler.base.TylerModelInterpretationContext;
042import com.squareup.javapoet.MethodSpec;
043
044public class TimestampModelHandler extends ModelHandlerBase {
045
046    boolean inError = false;
047    static final String TIMESTAMP_METHOD_NAME = "timestamp";
048    public TimestampModelHandler(Context context) {
049        super(context);
050    }
051
052    static public ModelHandlerBase makeInstance(Context context, ModelInterpretationContext ic) {
053        return new TimestampModelHandler(context);
054    }
055
056
057    @Override
058    protected Class<TimestampModel> getSupportedModelClass() {
059        return TimestampModel.class;
060    }
061
062    @Override
063    public void handle(ModelInterpretationContext mic, Model model) throws ModelHandlerException {
064        TimestampModel timestampModel = (TimestampModel) model;
065        TylerModelInterpretationContext tmic = (TylerModelInterpretationContext) mic;
066        String keyStr = timestampModel.getKey();
067        if (OptionHelper.isNullOrEmptyOrAllSpaces(keyStr)) {
068            addError("Attribute named [" + Action.KEY_ATTRIBUTE + "] cannot be empty");
069            inError = true;
070        }
071
072        String datePatternStr = timestampModel.getDatePattern();
073        if (OptionHelper.isNullOrEmptyOrAllSpaces(datePatternStr)) {
074            addError("Attribute named [" + TimestampAction.DATE_PATTERN_ATTRIBUTE + "] cannot be empty");
075            inError = true;
076        }
077
078        if(inError) {
079            addError("Skipping method generation for timestamp. Line " + model.getLineNumber());
080            return;
081        }
082
083        addJavaStatement(tmic, timestampModel);
084    }
085
086    void addJavaStatement(TylerModelInterpretationContext tmic, TimestampModel timestampModel) {
087        String scopeStr = timestampModel.getScopeStr();
088        if(scopeStr == null) {
089            scopeStr = "";
090        }
091        final String keyStr = timestampModel.getKey();
092        final String scopeVarName = "scope";
093        final String datePatternStr = timestampModel.getDatePattern();
094        final String cdfVarName = "cdf";
095        final String timevalVarName = "timeValue";
096        String timeReferenceVarName = "timeReference";
097
098        final String timeReferenceStr = timestampModel.getTimeReference();
099
100
101
102        MethodSpec.Builder timestampMethodSpecBuilder = MethodSpec.methodBuilder(toMethodName(keyStr)).
103                returns(void.class)
104                .addStatement("$T $N = $T.stringToScope($S)", ActionUtil.Scope.class, scopeVarName, ActionUtil.class,
105                        scopeStr)
106                .addStatement("$1T $2N = new $1T($3S)", CachingDateFormatter.class, cdfVarName, datePatternStr);
107
108        if (TimestampModel.CONTEXT_BIRTH.equalsIgnoreCase(timeReferenceStr)) {
109            timestampMethodSpecBuilder.addStatement("addInfo(\"Using context birth as time reference.\"");
110            timestampMethodSpecBuilder.addStatement("long $N = $N.getBirthTime()", timeReferenceVarName, tmic.getContextFieldSpec());
111        } else {
112            timestampMethodSpecBuilder.addStatement("long $N = System.currentTimeMillis()", timeReferenceVarName);
113            timestampMethodSpecBuilder.addStatement("addInfo(\"Using current interpretation time, i.e. now, as time reference.\")");
114        }
115
116        timestampMethodSpecBuilder.addStatement("String $N = $N.format($N)", timevalVarName, cdfVarName, timeReferenceVarName);
117
118        timestampMethodSpecBuilder.addStatement("addInfo(\"Adding property to the context with key='\"+$S+\"' and value=\"+$N+\" to the \"+$N+\" scope\")"
119                , keyStr, timevalVarName, scopeVarName);
120
121        timestampMethodSpecBuilder.addStatement("$T.setProperty(this, $S, $N, $N)", ActionUtil.class, keyStr, timevalVarName, scopeVarName);
122
123        MethodSpec timestampMethodSpec = timestampMethodSpecBuilder.build();
124        tmic.tylerConfiguratorTSB.addMethod(timestampMethodSpec);
125        tmic.configureMethodSpecBuilder.addStatement("$N()", timestampMethodSpec);
126
127    }
128
129    String toMethodName(String k) {
130        return TIMESTAMP_METHOD_NAME+'_'+k;
131    }
132}