/*
 * Copyright 1999-2023 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.nacos.logger.adapter.logback12;

import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.event.SaxEvent;
import ch.qos.logback.core.joran.spi.ElementSelector;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.joran.spi.RuleStore;
import com.alibaba.nacos.common.logging.NacosLoggingProperties;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

/**
 * ensure that Nacos configuration does not affect user configuration savepoints and  scanning url.
 *
 * @author <a href="mailto:hujun3@xiaomi.com">hujun</a>
 * @see <a href="https://github.com/alibaba/nacos/issues/6999">#6999</a>
 */
public class NacosLogbackConfiguratorAdapterV1 extends JoranConfigurator {
    
    private NacosLoggingProperties loggingProperties;
    
    public void setLoggingProperties(NacosLoggingProperties loggingProperties) {
        this.loggingProperties = loggingProperties;
    }
    
    /**
     * ensure that Nacos configuration does not affect user configuration savepoints.
     *
     * @param eventList safe data
     */
    @Override
    public void registerSafeConfiguration(List<SaxEvent> eventList) {
    }
    
    @Override
    public void addInstanceRules(RuleStore rs) {
        super.addInstanceRules(rs);
        rs.addRule(new ElementSelector("configuration/nacosClientProperty"),
                new NacosClientPropertyAction(loggingProperties));
    }
    
    /**
     * ensure that Nacos configuration does not affect user configuration scanning url.
     *
     * @param url config url
     * @throws Exception e
     */
    public void configure(URL url) throws Exception {
        InputStream in = null;
        try {
            URLConnection urlConnection = url.openConnection();
            urlConnection.setUseCaches(false);
            in = urlConnection.getInputStream();
            if (hasNewDoConfigureApi()) {
                doConfigure(in, url.toExternalForm());
            } else {
                // adapter old version of logback below 1.1.10
                doConfigure(in);
            }
        } catch (IOException ioe) {
            String errMsg = "Could not open URL [" + url + "].";
            addError(errMsg, ioe);
            throw new JoranException(errMsg, ioe);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ioe) {
                    String errMsg = "Could not close input stream";
                    addError(errMsg, ioe);
                    throw new JoranException(errMsg, ioe);
                }
            }
        }
    }
    
    /**
     * Since logback 1.1.10, Add new doConfigure API with sax systemId and use this API to do configure.
     *
     * @return {@code true} when logback is upper 1.1.10, otherwise {@code false}
     */
    private boolean hasNewDoConfigureApi() {
        try {
            this.getClass().getMethod("doConfigure", InputStream.class, String.class);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }
}
