<commit_before>/* $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;

import java.net.URL;

import org.apache.commons.digester3.Rule;
import org.apache.commons.digester3.binder.RulesBinder;
import org.apache.commons.digester3.binder.RulesModule;
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
        final String fileName = attributes.getValue( "path" );
        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 );
                }
                final URL classPathResource = this.targetRulesBinder.getContextClassLoader().getResource( path );
                if ( classPathResource == null )
                {
                    targetRulesBinder.addError( "Resource '%s' not found, please make sure it is in the classpath",
                                                path );
                }
                else
                {
                    fromXmlRulesModule = new FromXmlRulesModule()
                    {

                        @Override
                        protected void loadRules()
                        {
                            loadXMLRules( classPathResource );
                        }

                    };
                }
            }
            else
            {
                try
                {
                    fromXmlRulesModule = new FromXmlRulesModule()
                    {

                        @Override
                        protected void loadRules()
                        {
                            loadXMLRules( fileName );
                        }

                    };
                }
                catch ( Exception e )
                {
                    targetRulesBinder.addError( "An error occurred while inculing file from '%s': %s", fileName,
                                                e.getMessage() );
                }
            }

            if ( fromXmlRulesModule != null )
            {
                boolean circularFileInclusionDetected = false;
                for ( String systemId : fromXmlRulesModule.getSystemIds() )
                {
                    if ( !memoryRulesBinder.getIncludedFiles().add( systemId ) )
                    {
                        targetRulesBinder.addError( "Circular file inclusion detected for XML rules: %s", systemId );
                        circularFileInclusionDetected = true;
                    }
                }

                if ( !circularFileInclusionDetected )
                {
                    install( fromXmlRulesModule );
                }
            }<commit_msg>include rule simplified, checking if a URL has been already visited is simpler<commit_after>/* $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;

import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.digester3.Rule;
import org.apache.commons.digester3.binder.RulesBinder;
import org.apache.commons.digester3.binder.RulesModule;
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( "path" );
        if ( fileName != null && fileName.length() > 0 )
        {
            final URL xmlRulesResource;

            if ( fileName.startsWith( CLASSPATH_URL_PREFIX ) )
            {
                String path = fileName.substring( CLASSPATH_URL_PREFIX.length() );
                if ( '/' == path.charAt( 0 ) )
                {
                    path = path.substring( 1 );
                }
                xmlRulesResource = this.targetRulesBinder.getContextClassLoader().getResource( path );
                if ( xmlRulesResource == null )
                {
                    targetRulesBinder.addError( "Resource '%s' not found, please make sure it is in the classpath",
                                                path );
                    return;
                }
            }
            else
            {
                try
                {
                    xmlRulesResource = new URL( fileName );
                }
                catch ( MalformedURLException e )
                {
                    targetRulesBinder.addError( "An error occurred while inculing file from '%s': %s", fileName,
                                                e.getMessage() );
                    return;
                }
            }

            if ( memoryRulesBinder.getIncludedFiles().add( xmlRulesResource.toString() ) )
            {
                install( new FromXmlRulesModule()
                {

                    @Override
                    protected void loadRules()
                    {
                        loadXMLRules( xmlRulesResource );
                    }

                });
            }
            else
            {
                targetRulesBinder.addError( "Circular file inclusion detected for XML rules: %s", xmlRulesResource );
            }
{'fraction_non_alphanumeric': 0.06778530947883098, 'fraction_numerical': 0.002444716079564396, 'mean_word_length': 1.7363940407418668, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 13}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5832446', 'n_tokens_mistral': 2137, 'n_tokens_neox': 2045, 'n_words': 714}