/* $Id$
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.commons.digester3.xmlrules.metaparser;

import java.net.URL;

import org.apache.commons.digester3.Rule;
import org.apache.commons.digester3.RulesBinder;
import org.apache.commons.digester3.RulesModule;
import org.apache.commons.digester3.xmlrules.FromXmlRulesModule;
import org.xml.sax.Attributes;

/**
 * A rule for including one rules XML file within another. Included files
 * behave as if they are 'macro-expanded' within the includer. This means
 * that the values of the pattern stack are prefixed to every pattern
 * in the included rules. <p>This rule will detect 'circular' includes,
 * which would result in infinite recursion. It throws a
 * CircularIncludeException when a cycle is detected, which will terminate
 * the parse.
 */
final class IncludeRule extends Rule {

    private static final String CLASSPATH_URL_PREFIX = "classpath:";

    private final WithMemoryRulesBinder memoryRulesBinder;

    private final RulesBinder targetRulesBinder;

    public IncludeRule(final WithMemoryRulesBinder memoryRulesBinder, final RulesBinder targetRulesBinder) {
        this.memoryRulesBinder = memoryRulesBinder;
        this.targetRulesBinder = targetRulesBinder;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void begin(String namespace, String name, Attributes attributes) throws Exception {
        // The path attribute gives the URI to another digester rules xml file
        String fileName = attributes.getValue("url");
        if (fileName != null && fileName.length() > 0) {
            FromXmlRulesModule fromXmlRulesModule = null;

            if (fileName.startsWith(CLASSPATH_URL_PREFIX)) {
                String path = fileName.substring(CLASSPATH_URL_PREFIX.length());
                if ('/' == path.charAt(0)) {
                    path = path.substring(1);
                }
                fromXmlRulesModule = new FromXmlRulesModule(path);
            } else {
                try {
                    fromXmlRulesModule = new FromXmlRulesModule(new URL(fileName));
                } catch (Exception e) {
                    this.targetRulesBinder.addError("An error occurred while inculing file from '%s': %s",
                            fileName,
                            e.getMessage());
                }
            }

            if (fromXmlRulesModule != null) {
                if (!this.memoryRulesBinder.getIncludedFiles().add(fromXmlRulesModule.getSystemId())) {
                    this.targetRulesBinder.addError("Circular file inclusion detected for XML rules: %s",
                            fromXmlRulesModule.getSystemId());
                } else {
                    this.install(fromXmlRulesModule);
                }
            }
        }

        // The class attribute gives the name of a class that implements
        // the DigesterRulesSource interface
        String className = attributes.getValue("class");
        if (className != null && className.length() > 0) {
            try {
                Class<?> cls = Class.forName(className);
                if (!RulesModule.class.isAssignableFrom(cls)) {
                    this.targetRulesBinder.addError("Class '%s' if not a '%s' implementation",
                            className,
                            RulesModule.class.getName());
                    return;
                }

                RulesModule rulesSource = (RulesModule) cls.newInstance();

                this.install(rulesSource);
            } catch (Exception e) {
                this.targetRulesBinder.addError("Impossible to include programmatic rules from class '%s': %s",
                        className,
                        e.getMessage());
            }
        }
    }

    private void install(RulesModule rulesModule) {
        // that's an hack, shall not be taken in consideration!!! :)
        rulesModule.configure(
                new PrefixedRulesBinder(this.targetRulesBinder, this.memoryRulesBinder.getPatternStack().toString()));
    }

}

@@ -2644,32 +2644,371 @@
               %7D%0A
+                URL classPathResource = this.targetRulesBinder.getContextClassLoader().getResource(path);%0A                if (classPathResource == null) %7B%0A                    this.targetRulesBinder.addError(%22Resource '%25s' not found, please make sure it is in the classpath%22,%0A                            path);%0A                %7D else %7B%0A    
                 
@@ -3051,22 +3051,53 @@
 sModule(
-path);
+classPathResource);%0A                %7D
 %0A       

use the context class loader to retrieve resources have to be included