001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v2.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.joran.action;
015
016import ch.qos.logback.core.CoreConstants;
017import ch.qos.logback.core.joran.JoranConstants;
018import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
019import ch.qos.logback.core.model.ConversionRuleModel;
020import ch.qos.logback.core.model.Model;
021import ch.qos.logback.core.util.OptionHelper;
022import org.xml.sax.Attributes;
023
024import java.util.HashMap;
025import java.util.Map;
026
027import static ch.qos.logback.core.joran.JoranConstants.CONVERSION_WORD_ATTRIBUTE;
028
029public class ConversionRuleAction extends BaseModelAction {
030
031    static public String CONVERTER_CLASS_ATTRIBUTE = "converterClass";
032
033
034    @Override
035    protected boolean validPreconditions(SaxEventInterpretationContext seic, String name, Attributes attributes) {
036        PreconditionValidator pv = new PreconditionValidator(this, seic, name, attributes);
037
038        pv.validateGivenAttribute(CONVERSION_WORD_ATTRIBUTE);
039
040        if(!pv.isValid()) {
041            // no point in going further if the conversion word is not specified
042            return false;
043        }
044
045        boolean validConverterClassAttribute = pv.isValidAttribute(CONVERTER_CLASS_ATTRIBUTE);
046        boolean validClassAttribute = pv.isValidAttribute(CLASS_ATTRIBUTE);
047
048        boolean multipleClassAttributes = (validClassAttribute) && (validConverterClassAttribute);
049        
050        // If both attributes are specified, silently use 'class' (for backward compatibility)
051        // Do not warn about deprecation when 'class' is present
052        if(validConverterClassAttribute && !multipleClassAttributes) {
053            pv.addWarn("["+CONVERTER_CLASS_ATTRIBUTE +"] attribute is deprecated and replaced by ["+CLASS_ATTRIBUTE+
054                    "]. "+pv.getLocationSuffix());
055        }
056        
057        boolean missingClass = !validClassAttribute && !validConverterClassAttribute;
058        if(missingClass) {
059            pv.addMissingAttributeError(CLASS_ATTRIBUTE);
060            return false;
061        }
062
063        if(multipleClassAttributes) {
064            String converterClass = attributes.getValue(CONVERTER_CLASS_ATTRIBUTE);
065            String classAttr = attributes.getValue(CLASS_ATTRIBUTE);
066            if (!converterClass.equals(classAttr)) {
067                pv.addWarn("Both ["+CONVERTER_CLASS_ATTRIBUTE+"] and ["+CLASS_ATTRIBUTE+"] attributes are specified but have different values.");
068            } else {
069                pv.addInfo("Both [" + CONVERTER_CLASS_ATTRIBUTE + "] attribute and [" + CLASS_ATTRIBUTE + "] attribute specified. ");
070            }
071            pv.addInfo( "["+CLASS_ATTRIBUTE+"] attribute will be used. ");
072        }
073        pv.validateGivenAttribute(CONVERSION_WORD_ATTRIBUTE);
074        return pv.isValid();
075    }
076
077
078
079    @Override
080    protected Model buildCurrentModel(SaxEventInterpretationContext interpretationContext, String name,
081            Attributes attributes) {
082        ConversionRuleModel conversionRuleModel = new ConversionRuleModel();
083        conversionRuleModel.setConversionWord(attributes.getValue(CONVERSION_WORD_ATTRIBUTE));
084
085        String converterClassStr = attributes.getValue(CONVERTER_CLASS_ATTRIBUTE);
086        if(!OptionHelper.isNullOrEmpty(converterClassStr)) {
087            conversionRuleModel.setClassName(converterClassStr);
088        }
089        // if both converterClass and class are specified the latter overrides.
090        String classStr = attributes.getValue(CLASS_ATTRIBUTE);
091        if(!OptionHelper.isNullOrEmpty(classStr)) {
092            conversionRuleModel.setClassName(classStr);
093        }
094        return conversionRuleModel;
095    }
096
097//    /**
098//     * Instantiates a layout of the given class and sets its name.
099//     *
100//     */
101//    @SuppressWarnings("unchecked")
102//    public void begin(SaxEventInterpretationContext ec, String localName, Attributes attributes) {
103//        // Let us forget about previous errors (in this object)
104//        inError = false;
105//
106//        String errorMsg;
107//        String conversionWord = attributes.getValue(CONVERSION_WORD_ATTRIBUTE);
108//        String converterClass = attributes.getValue(JoranConstants.CONVERTER_CLASS_ATTRIBUTE);
109//
110//        if (OptionHelper.isNullOrEmptyOrAllSpaces(conversionWord)) {
111//            inError = true;
112//            errorMsg = "No 'conversionWord' attribute in <conversionRule>";
113//            addError(errorMsg);
114//
115//            return;
116//        }
117//
118//        if (OptionHelper.isNullOrEmptyOrAllSpaces(converterClass)) {
119//            inError = true;
120//            errorMsg = "No 'converterClass' attribute in <conversionRule>";
121//            ec.addError(errorMsg);
122//
123//            return;
124//        }
125//
126//        try {
127//            Map<String, String> ruleRegistry = (Map<String, String>) context
128//                    .getObject(CoreConstants.PATTERN_RULE_REGISTRY);
129//            if (ruleRegistry == null) {
130//                ruleRegistry = new HashMap<String, String>();
131//                context.putObject(CoreConstants.PATTERN_RULE_REGISTRY, ruleRegistry);
132//            }
133//            // put the new rule into the rule registry
134//            addInfo("registering conversion word " + conversionWord + " with class [" + converterClass + "]");
135//            ruleRegistry.put(conversionWord, converterClass);
136//        } catch (Exception oops) {
137//            inError = true;
138//            errorMsg = "Could not add conversion rule to PatternLayout.";
139//            addError(errorMsg);
140//        }
141//    }
142//
143//
144//    /**
145//     * Once the children elements are also parsed, now is the time to activate the
146//     * appender options.
147//     */
148//    public void end(SaxEventInterpretationContext ec, String n) {
149//    }
150//
151//    public void finish(SaxEventInterpretationContext ec) {
152//    }
153}