de.codesourcery.spring.contextrewrite.RewriteConfig.java Source code

Java tutorial

Introduction

Here is the source code for de.codesourcery.spring.contextrewrite.RewriteConfig.java

Source

/**
 * Copyright 2015 Tobias Gierke <tobias.gierke@code-sourcery.de>
 *
 * 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 de.codesourcery.spring.contextrewrite;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.Validate;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

import de.codesourcery.spring.contextrewrite.XMLRewrite.Rule;

/**
 * Holds all configuration options and rules that should be applied during XML rewriting.
 *
 * @author tobias.gierke@code-sourcery.de
 */
public class RewriteConfig {
    private final List<Rule> anonRules = new ArrayList<>();
    private final Map<String, Rule> namedRules = new HashMap<>();

    private final Class<?> clazz;

    private RewriteConfig parent;

    private String contextPath;
    private Boolean debug;
    private Boolean dumpXML;

    /**
     * Create instance.
     */
    public RewriteConfig() {
        this.clazz = null;
    }

    /**
     * Create instance associated with a given class.
     * 
     * <p>The class instance is currently only used for informational purposes.</p>
     * 
     * @param clazz associated class, never <code>null</code>
     */
    public RewriteConfig(Class<?> clazz) {
        Validate.notNull(clazz, "class must not be NULL");
        this.clazz = clazz;
    }

    /**
     * Sets the parent of this configuration.
     * 
     * <p>If a parent configuration is set, any information missing in the child instance
     * will be looked-up from the parent.</p>
     * 
     * @param parent parent configuration , never <code>null</code>
     */
    public void setParent(RewriteConfig parent) {
        Validate.notNull(parent, "parent must not be NULL");
        this.parent = parent;
    }

    /**
     * Returns whether this configuration or any of its parents has at least one rewriting rule.
     * 
     * @return
     */
    public boolean hasRules() {
        return !hasNoRules();
    }

    /**
     * Returns whether this configuration nor any of its parents has any rewriting rules.
     * 
     * @return
     */
    public boolean hasNoRules() {
        if (anonRules.isEmpty() && namedRules.isEmpty()) {
            return parent == null ? true : parent.hasNoRules();
        }
        return false;
    }

    /**
     * Add rewriting rule.
     * 
     * @param rule
     * @throws IllegalStateException if this rule has an ID that clashes with another rule that has already been added to this instance. Anonymous rules (rules without an ID) can
     * never clash.
     */
    public void addRule(Rule rule) throws IllegalStateException {

        Validate.notNull(rule, "rule must not be NULL");
        if (rule.isIDNotSet()) {
            anonRules.add(rule);
            return;

        }
        if (namedRules.containsKey(rule.id)) {
            final String msg = "Rule with duplicate ID '" + rule.id + "'"
                    + (clazz != null ? " on class " + clazz : "");
            throw new IllegalStateException(msg);
        }
        this.namedRules.put(rule.id, rule);
    }

    /**
     * Add rewriting rules.
     * 
     * @param rules
     * @throws IllegalStateException if any of the rules has an ID that clashes with another rule that has already been added to this instance. Anonymous rules (rules without an ID) can
     * never clash.
     */
    public void addRules(Collection<Rule> rules) throws IllegalStateException {

        Validate.notNull(rules, "rule must not be NULL");
        rules.forEach(this::addRule);
    }

    /**
     * Returns all rewriting rules of this instance merged with any rules from parent instances.
     * 
     * <p>
     * Merging is done by applying the following algorithm:
     * 
     * 1.) Gather all anonymous rules (=rules without an explicit ID) 
     * 2.) Gather all named rules (=rules with an ID set) from <b>this</b> instance
     * 3.) Recursively gather named rules from parent configurations (if any) as long as they do no clash with the ID of a named rule
     *     that has already been merged
     * </p>
     *  
     * @return
     */
    public List<Rule> getRules() {
        final List<Rule> result = new ArrayList<>(Math.max(1, anonRules.size() + namedRules.size()));

        result.addAll(anonRules);
        result.addAll(namedRules.values());

        final Set<String> ruleIDs = new HashSet<>(namedRules.keySet());

        if (parent != null) {
            final List<Rule> parentRules = parent.getRules();
            parentRules.stream().filter(Rule::isIDNotSet).forEach(result::add);
            parentRules.stream().filter(Rule::isIDSet).filter(rule -> !ruleIDs.contains(rule.id))
                    .peek(r -> ruleIDs.add(r.id)).forEach(result::add);
        }
        return result;
    }

    /**
     * Returns the abstract path to the XML file that should be rewritten.
     *  
     * @return
     * @throws IllegalStateException if neither this configuration nor any of its parents has a non-blank context path.
     */
    public String getContextPath() throws IllegalStateException {
        if (contextPath != null) {
            return contextPath;
        }
        if (parent != null) {
            return parent.getContextPath();
        }
        throw new IllegalStateException("Context path not set?");
    }

    /**
     * Returns a Spring <code>Resource</code> that can be used to retrieve the XML that should be rewritten.
     *  
     * @return
     * @throws IllegalStateException if neither this configuration nor any of its parents has a non-blank context path.
     */
    public Resource getResource() throws IllegalStateException {
        final String path = getContextPath();
        if (path.startsWith("file:")) {
            return new FileSystemResource(path.substring("file:".length()));
        }
        return new ClassPathResource(path);
    }

    /**
     * Sets the abstract path to the XML that should be rewritten.
     * 
     * @param contextPath context path, never <code>null</code> or blank
     * @throws IllegalArgumentException if the context path was blank
     * @throws NullPointerException if the context path was <code>null</code>
     */
    public void setContextPath(String contextPath) {
        Validate.notBlank(contextPath, "contextPath must not be NULL or blank");
        this.contextPath = contextPath;
    }

    /**
     * Enable/disable debug output to std out.
     * 
     * <p>This is most useful for debugging this project.</p>
     * 
     * @param debug
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    /**
     * Returns whether debug output should be printed to std out.
     * 
     * @return
     */
    public boolean isDebug() {
        if (debug != null) {
            return debug.booleanValue();
        }
        return parent != null ? parent.isDebug() : false;
    }

    /**
     * Set whether the transformed XML should be printed to std out.
     * @param dumpXML
     */
    public void setDumpXML(boolean dumpXML) {
        this.dumpXML = dumpXML;
    }

    /**
     * Returns whether the transformed XML should be printed to std out. 
     * @return
     */
    public boolean isDumpXML() {
        if (dumpXML != null) {
            return dumpXML.booleanValue();
        }
        return parent != null ? parent.isDumpXML() : false;
    }
}