io.mycat.config.loader.xml.XMLRuleLoader.java Source code

Java tutorial

Introduction

Here is the source code for io.mycat.config.loader.xml.XMLRuleLoader.java

Source

/*
 * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software;Designed and Developed mainly by many Chinese 
 * opensource volunteers. you can redistribute it and/or modify it under the 
 * terms of the GNU General Public License version 2 only, as published by the
 * Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Any questions about this component can be directed to it's project Web address 
 * https://code.google.com/p/opencloudb/.
 *
 */
package io.mycat.config.loader.xml;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLSyntaxErrorException;
import java.util.*;

import io.mycat.config.loader.zkprocess.entity.rule.tablerule.Rule;
import org.apache.commons.lang.ArrayUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import io.mycat.config.model.rule.RuleConfig;
import io.mycat.config.model.rule.TableRuleConfig;
import io.mycat.config.util.ConfigException;
import io.mycat.config.util.ConfigUtil;
import io.mycat.config.util.ParameterMapping;
import io.mycat.route.function.AbstractPartitionAlgorithm;
import io.mycat.util.SplitUtil;

/**
 * @author mycat
 */
@SuppressWarnings("unchecked")
public class XMLRuleLoader {
    private final static String DEFAULT_DTD = "/rule.dtd";
    private final static String DEFAULT_XML = "/rule.xml";

    private final Map<String, TableRuleConfig> tableRules;
    // private final Set<RuleConfig> rules;
    private final Map<String, AbstractPartitionAlgorithm> functions;

    public XMLRuleLoader(String ruleFile) {
        // this.rules = new HashSet<RuleConfig>();
        //rule?? -> rule
        this.tableRules = new HashMap<String, TableRuleConfig>();
        //function?? -> 
        this.functions = new HashMap<String, AbstractPartitionAlgorithm>();
        load(DEFAULT_DTD, ruleFile == null ? DEFAULT_XML : ruleFile);
    }

    public XMLRuleLoader() {
        this(null);
    }

    public Map<String, TableRuleConfig> getTableRules() {
        return (Map<String, TableRuleConfig>) (tableRules.isEmpty() ? Collections.emptyMap() : tableRules);
    }

    private void load(String dtdFile, String xmlFile) {
        InputStream dtd = null;
        InputStream xml = null;
        try {
            dtd = XMLRuleLoader.class.getResourceAsStream(dtdFile);
            xml = XMLRuleLoader.class.getResourceAsStream(xmlFile);
            //??
            Element root = ConfigUtil.getDocument(dtd, xml).getDocumentElement();
            //Function
            loadFunctions(root);
            //TableRule
            loadTableRules(root);
        } catch (ConfigException e) {
            throw e;
        } catch (Exception e) {
            throw new ConfigException(e);
        } finally {
            if (dtd != null) {
                try {
                    dtd.close();
                } catch (IOException e) {
                }
            }
            if (xml != null) {
                try {
                    xml.close();
                } catch (IOException e) {
                }
            }
        }
    }

    /**
     * tableRule
     * <tableRule name="sharding-by-month">
     *     <rule>
     *         <columns>create_date</columns>
     *         <algorithm>partbymonth</algorithm>
     *     </rule>
     * </tableRule>
     * @param root
     * @throws SQLSyntaxErrorException
      */
    private void loadTableRules(Element root) throws SQLSyntaxErrorException {
        //??tableRule
        NodeList list = root.getElementsByTagName("tableRule");
        for (int i = 0, n = list.getLength(); i < n; ++i) {
            Node node = list.item(i);
            if (node instanceof Element) {
                Element e = (Element) node;
                //???
                String name = e.getAttribute("name");
                if (tableRules.containsKey(name)) {
                    throw new ConfigException("table rule " + name + " duplicated!");
                }
                //?rule
                NodeList ruleNodes = e.getElementsByTagName("rule");
                int length = ruleNodes.getLength();
                //            if (length > 1) {
                //               throw new ConfigException("only one rule can defined :"
                //                     + name);
                //            }
                //???????
                //RuleConfig??rulefunction
                RuleConfig[] rules = new RuleConfig[length];
                for (int j = 0; j < length; j++) {
                    RuleConfig rule = loadRule((Element) ruleNodes.item(j));
                    String funName = rule.getFunctionName();
                    //function??function
                    AbstractPartitionAlgorithm func = functions.get(funName);
                    if (func == null) {
                        throw new ConfigException("can't find function of name :" + funName);
                    }
                    rule.setRuleAlgorithm(func);
                    rules[j] = rule;
                }

                //?tableRules
                tableRules.put(name, new TableRuleConfig(name, rules[0], rules));
            }
        }
    }

    private RuleConfig loadRule(Element element) throws SQLSyntaxErrorException {
        //?columns
        Element columnsEle = ConfigUtil.loadElement(element, "columns");
        String column = columnsEle.getTextContent();
        String[] columns = SplitUtil.split(column, ',', true);
        if (columns.length > 1) {
            throw new ConfigException("table rule coulmns has multi values:" + columnsEle.getTextContent());
        }
        //?algorithm
        Element algorithmEle = ConfigUtil.loadElement(element, "algorithm");
        String algorithm = algorithmEle.getTextContent();
        return new RuleConfig(column.toUpperCase(), algorithm);
    }

    /**
     * function
     * <function name="partbymonth" class="io.mycat.route.function.PartitionByMonth">
     *     <property name="dateFormat">yyyy-MM-dd</property>
     *     <property name="sBeginDate">2015-01-01</property>
     * </function>
     * @param root
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
      */
    private void loadFunctions(Element root) throws ClassNotFoundException, InstantiationException,
            IllegalAccessException, InvocationTargetException {
        NodeList list = root.getElementsByTagName("function");
        for (int i = 0, n = list.getLength(); i < n; ++i) {
            Node node = list.item(i);
            if (node instanceof Element) {
                Element e = (Element) node;
                //?name
                String name = e.getAttribute("name");
                //Mapfunction??
                if (functions.containsKey(name)) {
                    throw new ConfigException("rule function " + name + " duplicated!");
                }
                //?class
                String clazz = e.getAttribute("class");
                //?class??
                AbstractPartitionAlgorithm function = createFunction(name, clazz);
                //????
                ParameterMapping.mapping(function, ConfigUtil.loadElements(e));
                //?AbstractPartitionAlgorithm?init??
                function.init();
                //functions map
                functions.put(name, function);
            }
        }
    }

    private AbstractPartitionAlgorithm createFunction(String name, String clazz) throws ClassNotFoundException,
            InstantiationException, IllegalAccessException, InvocationTargetException {
        Class<?> clz = Class.forName(clazz);
        //?AbstractPartitionAlgorithm
        if (!AbstractPartitionAlgorithm.class.isAssignableFrom(clz)) {
            throw new IllegalArgumentException("rule function must implements "
                    + AbstractPartitionAlgorithm.class.getName() + ", name=" + name);
        }
        return (AbstractPartitionAlgorithm) clz.newInstance();
    }

}