<commit_before>package bitronix.tm.resource;

import bitronix.tm.TransactionManagerServices;
import bitronix.tm.utils.InitializationException;
import bitronix.tm.utils.PropertyUtils;
import bitronix.tm.utils.Service;
import bitronix.tm.resource.common.XAResourceProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jms.XAConnectionFactory;
import javax.sql.XADataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

/**
 * XA resources pools configurator & loader.
 * <p>{@link ResourceLoader} relies on the optional <code>bitronix.tm.resource.configuration</code> propery to load the
 * JDBC datasources ({@link bitronix.tm.resource.jdbc.PoolingDataSource}) and JMS connection factories configuration
 * ({@link bitronix.tm.resource.jms.PoolingConnectionFactory}) file and create the resources.</p>
 * <p>There is an optional <code>bitronix.tm.resource.bind</code> property that makes ResourceLoader bind resources
 * to JNDI.</p>
 * <p>When <code>bitronix.tm.resource.configuration</code> is not specified, ResourceLoader is disabled and resources
 * should be manually created.</p>
 * <p>&copy; Bitronix 2005, 2006, 2007</p>
 *
 * @author lorban
 */
public class ResourceLoader implements Service {

    private final static Logger log = LoggerFactory.getLogger(ResourceLoader.class);

    private final static String JDBC_RESOURCE_CLASSNAME = "bitronix.tm.resource.jdbc.PoolingDataSource";
    private final static String JMS_RESOURCE_CLASSNAME = "bitronix.tm.resource.jms.PoolingConnectionFactory";

    private Map resourcesByUniqueName;

    public ResourceLoader() {
    }

    /**
     * Get a Map with the configured uniqueName as key and {@link XAResourceProducer} as value.
     * @return a Map using the uniqueName as key and {@link XAResourceProducer} as value.
     */
    public Map getResources() {
        return resourcesByUniqueName;
    }

    /**
     * Initialize the ResourceLoader and load the resources configuration file specified in
     * <code>bitronix.tm.resource.configuration</code> property.
     * @return the number of resources which failed to initialize.
     */
    public int init() {
        String filename = TransactionManagerServices.getConfiguration().getResourceConfigurationFilename();
        if (filename != null) {
            if (!new File(filename).exists())
                throw new ResourceConfigurationException("cannot find resources configuration file '" + filename + "', missing or invalid value of property: bitronix.tm.resource.configuration");
            log.info("reading resources configuration from " + filename);
            return init(filename);
        }
        else {
            if (log.isDebugEnabled()) log.debug("no resource configuration file specified");
            resourcesByUniqueName = Collections.EMPTY_MAP;
            return 0;
        }
    }

    public synchronized void shutdown() {
        if (log.isDebugEnabled()) log.debug("resource loader has registered " + resourcesByUniqueName.entrySet().size() + " resource(s), unregistering them now");
        Iterator it = resourcesByUniqueName.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            XAResourceProducer producer = (XAResourceProducer) entry.getValue();
            if (log.isDebugEnabled()) log.debug("closing " + producer);
            try {
                producer.close();
            } catch (Exception ex) {
                log.warn("error closing resource " + producer, ex);
            }
        }
        resourcesByUniqueName.clear();
    }

    /*
     * Internal impl.
     */

    /**
     * Create an unitialized {@link XAResourceProducer} implementation which depends on the XA resource class name.
     * @param xaResourceClassName an XA resource class name.
     * @return a {@link XAResourceProducer} implementation.
     * @throws ClassNotFoundException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws IllegalAccessException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws InstantiationException if the {@link XAResourceProducer} cannot be instanciated.
     */
    private static XAResourceProducer instanciate(String xaResourceClassName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class clazz = Thread.currentThread().getContextClassLoader().loadClass(xaResourceClassName);

        // resource classes are instanciated via reflection so that there is no hard class binding between this internal
        // transaction manager service and 3rd party libraries like the JMS ones.
        // This allows using the TM with a 100% JDBC application without requiring JMS libraries.

        if (XADataSource.class.isAssignableFrom(clazz)) {
            return (XAResourceProducer) Thread.currentThread().getContextClassLoader().loadClass(JDBC_RESOURCE_CLASSNAME).newInstance();
        }
        else if (XAConnectionFactory.class.isAssignableFrom(clazz)) {
            return (XAResourceProducer) Thread.currentThread().getContextClassLoader().loadClass(JMS_RESOURCE_CLASSNAME).newInstance();
        }
        else
            return null;
    }

    /**
     * Read the resources properties file and create {@link XAResourceProducer} accordingly.
     * @param propertiesFilename the name of the properties file to load.
     * @return the number of resources which failed to initialize.
     */
    private int init(String propertiesFilename) {
        try {
            FileInputStream fis = null;
            Properties properties;
            try {
                fis = new FileInputStream(propertiesFilename);
                properties = new Properties();
                properties.load(fis);
            } finally {
                if (fis != null) fis.close();
            }

            return initXAResourceProducers(properties);
        } catch (IOException ex) {
            throw new InitializationException("cannot create resource binder", ex);
        }
    }

    /**
     * Initialize {@link XAResourceProducer}s given a set of properties.
     * @param properties the properties to use for initialization.
     * @return the number of resources which failed to initialize.
     */
    int initXAResourceProducers(Properties properties) {
        Map entries = buildConfigurationEntriesMap(properties);
        int errorCount = 0;

        resourcesByUniqueName = new HashMap();
        for (Iterator it = entries.entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            String uniqueName = (String) entry.getKey();
            List propertyPairs = (List) entry.getValue();
            XAResourceProducer producer = buildXAResourceProducer(uniqueName, propertyPairs);

            if (ResourceRegistrar.get(producer.getUniqueName()) != null) {
                if (log.isDebugEnabled()) log.debug("resource already registered, skipping it:" + producer.getUniqueName());
                continue;
            }

            if (log.isDebugEnabled()) log.debug("creating resource " + producer);
            try {
                producer.init();
            } catch (ResourceConfigurationException ex) {
                log.warn("unable to create resource with unique name " + producer.getUniqueName(), ex);
                producer.close();
                errorCount++;
            }

            resourcesByUniqueName.put(producer.getUniqueName(), producer);
        }

        return errorCount;
    }

    /**
     * Create a map using the configured resource name as the key and a List of PropertyPair objects as the value.
     * @param properties object to analyze.
     * @return the built map.
     */
    private Map buildConfigurationEntriesMap(Properties properties) {
        Map entries = new HashMap();
        Iterator it = properties.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();

            if (key.startsWith("resource.")) {
                String[] keyParts = key.split("\\.");
                if (keyParts.length < 3 || keyParts.length > 4) {
                    log.warn("ignoring invalid entry in configuration file: " + key);
                    continue;
                }
                String configuredName = keyParts[1];
                String propertyName = keyParts[2];
                if (keyParts.length == 4) {
                    propertyName += "." + keyParts[3];
                }

                List pairs = (List) entries.get(configuredName);
                if (pairs == null) {
                    pairs = new ArrayList();
                    entries.put(configuredName, pairs);
                }

                pairs.add(new PropertyPair(propertyName, value));
            }
        }
        return entries;
    }

    /**
     * Build a populated {@link XAResourceProducer} out of a list of property pairs and the config name.
     * @param configuredName index name of the config file.
     * @param propertyPairs the properties attached to this index.
     * @return a populated {@link XAResourceProducer}.
     * @throws ResourceConfigurationException if the {@link XAResourceProducer} cannot be built.
     */
    private XAResourceProducer buildXAResourceProducer(String configuredName, List propertyPairs) throws ResourceConfigurationException {
        String lastPropertyName = "className";
        try {
            XAResourceProducer producer = createBean(configuredName, propertyPairs);

            for (int i = 0; i < propertyPairs.size(); i++) {
                PropertyPair propertyPair = (PropertyPair) propertyPairs.get(i);
                lastPropertyName = propertyPair.getName();
                String propertyValue = propertyPair.getValue();

                PropertyUtils.setProperty(producer, lastPropertyName, propertyValue);
            }
            if (producer.getUniqueName() == null)
                throw new ResourceConfigurationException("missing mandatory property <uniqueName> for resource <" + configuredName + "> in resources configuration file");

            return producer;
        } catch (ResourceConfigurationException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new ResourceConfigurationException("cannot configure resource for configuration entries with name <" + configuredName + ">" + " - failing property is <" + lastPropertyName + ">", ex);
        }
    }

    /**
     * Create an unpopulated, uninitialized {@link XAResourceProducer} instance depending on the className value.
     * @param configuredName the properties configured name.
     * @param propertyPairs a list of {@link PropertyPair}s.
     * @return a {@link XAResourceProducer}.
     * @throws ClassNotFoundException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws IllegalAccessException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws InstantiationException if the {@link XAResourceProducer} cannot be instanciated.
     */
    private XAResourceProducer createBean(String configuredName, List propertyPairs) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        for (int i = 0; i < propertyPairs.size(); i++) {
            PropertyPair propertyPair = (PropertyPair) propertyPairs.get(i);
            if (propertyPair.getName().equals("className")) {
                String className = propertyPair.getValue();
                XAResourceProducer producer = instanciate(className);
                if (producer == null)
                    throw new ResourceConfigurationException("property <className> " +
                            "for resource <" + configuredName + "> in resources configuration file " +
                            "must be the name of a class implementing either javax.sql.XADataSource or javax.jms.XAConnectionFactory");
                return producer;
            }
        }
        throw new ResourceConfigurationException("missing mandatory property <className> for resource <" + configuredName + "> in resources configuration file");
    }


    private class PropertyPair {
        private String name;
        private String value;

        public PropertyPair(String key, String value) {
            this.name = key;
            this.value = value;
        }

        public String getName() {
            return name;
        }

        public String getValue() {
            return value;
        }

        public String toString() {
            return name + "/" + value;
        }
    }

}
<commit_msg>fixed NPE when specified resource loader config file does not exist<commit_after>package bitronix.tm.resource;

import bitronix.tm.TransactionManagerServices;
import bitronix.tm.utils.InitializationException;
import bitronix.tm.utils.PropertyUtils;
import bitronix.tm.utils.Service;
import bitronix.tm.resource.common.XAResourceProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jms.XAConnectionFactory;
import javax.sql.XADataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

/**
 * XA resources pools configurator & loader.
 * <p>{@link ResourceLoader} relies on the optional <code>bitronix.tm.resource.configuration</code> propery to load the
 * JDBC datasources ({@link bitronix.tm.resource.jdbc.PoolingDataSource}) and JMS connection factories configuration
 * ({@link bitronix.tm.resource.jms.PoolingConnectionFactory}) file and create the resources.</p>
 * <p>There is an optional <code>bitronix.tm.resource.bind</code> property that makes ResourceLoader bind resources
 * to JNDI.</p>
 * <p>When <code>bitronix.tm.resource.configuration</code> is not specified, ResourceLoader is disabled and resources
 * should be manually created.</p>
 * <p>&copy; Bitronix 2005, 2006, 2007</p>
 *
 * @author lorban
 */
public class ResourceLoader implements Service {

    private final static Logger log = LoggerFactory.getLogger(ResourceLoader.class);

    private final static String JDBC_RESOURCE_CLASSNAME = "bitronix.tm.resource.jdbc.PoolingDataSource";
    private final static String JMS_RESOURCE_CLASSNAME = "bitronix.tm.resource.jms.PoolingConnectionFactory";

    private Map resourcesByUniqueName = Collections.EMPTY_MAP;

    public ResourceLoader() {
    }

    /**
     * Get a Map with the configured uniqueName as key and {@link XAResourceProducer} as value.
     * @return a Map using the uniqueName as key and {@link XAResourceProducer} as value.
     */
    public Map getResources() {
        return resourcesByUniqueName;
    }

    /**
     * Initialize the ResourceLoader and load the resources configuration file specified in
     * <code>bitronix.tm.resource.configuration</code> property.
     * @return the number of resources which failed to initialize.
     */
    public int init() {
        String filename = TransactionManagerServices.getConfiguration().getResourceConfigurationFilename();
        if (filename != null) {
            if (!new File(filename).exists())
                throw new ResourceConfigurationException("cannot find resources configuration file '" + filename + "', missing or invalid value of property: bitronix.tm.resource.configuration");
            log.info("reading resources configuration from " + filename);
            return init(filename);
        }
        else {
            if (log.isDebugEnabled()) log.debug("no resource configuration file specified");
            return 0;
        }
    }

    public synchronized void shutdown() {
        if (log.isDebugEnabled()) log.debug("resource loader has registered " + resourcesByUniqueName.entrySet().size() + " resource(s), unregistering them now");
        Iterator it = resourcesByUniqueName.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            XAResourceProducer producer = (XAResourceProducer) entry.getValue();
            if (log.isDebugEnabled()) log.debug("closing " + producer);
            try {
                producer.close();
            } catch (Exception ex) {
                log.warn("error closing resource " + producer, ex);
            }
        }
        resourcesByUniqueName.clear();
    }

    /*
     * Internal impl.
     */

    /**
     * Create an unitialized {@link XAResourceProducer} implementation which depends on the XA resource class name.
     * @param xaResourceClassName an XA resource class name.
     * @return a {@link XAResourceProducer} implementation.
     * @throws ClassNotFoundException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws IllegalAccessException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws InstantiationException if the {@link XAResourceProducer} cannot be instanciated.
     */
    private static XAResourceProducer instanciate(String xaResourceClassName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class clazz = Thread.currentThread().getContextClassLoader().loadClass(xaResourceClassName);

        // resource classes are instanciated via reflection so that there is no hard class binding between this internal
        // transaction manager service and 3rd party libraries like the JMS ones.
        // This allows using the TM with a 100% JDBC application without requiring JMS libraries.

        if (XADataSource.class.isAssignableFrom(clazz)) {
            return (XAResourceProducer) Thread.currentThread().getContextClassLoader().loadClass(JDBC_RESOURCE_CLASSNAME).newInstance();
        }
        else if (XAConnectionFactory.class.isAssignableFrom(clazz)) {
            return (XAResourceProducer) Thread.currentThread().getContextClassLoader().loadClass(JMS_RESOURCE_CLASSNAME).newInstance();
        }
        else
            return null;
    }

    /**
     * Read the resources properties file and create {@link XAResourceProducer} accordingly.
     * @param propertiesFilename the name of the properties file to load.
     * @return the number of resources which failed to initialize.
     */
    private int init(String propertiesFilename) {
        try {
            FileInputStream fis = null;
            Properties properties;
            try {
                fis = new FileInputStream(propertiesFilename);
                properties = new Properties();
                properties.load(fis);
            } finally {
                if (fis != null) fis.close();
            }

            return initXAResourceProducers(properties);
        } catch (IOException ex) {
            throw new InitializationException("cannot create resource binder", ex);
        }
    }

    /**
     * Initialize {@link XAResourceProducer}s given a set of properties.
     * @param properties the properties to use for initialization.
     * @return the number of resources which failed to initialize.
     */
    int initXAResourceProducers(Properties properties) {
        Map entries = buildConfigurationEntriesMap(properties);
        int errorCount = 0;

        resourcesByUniqueName = new HashMap();
        for (Iterator it = entries.entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            String uniqueName = (String) entry.getKey();
            List propertyPairs = (List) entry.getValue();
            XAResourceProducer producer = buildXAResourceProducer(uniqueName, propertyPairs);

            if (ResourceRegistrar.get(producer.getUniqueName()) != null) {
                if (log.isDebugEnabled()) log.debug("resource already registered, skipping it:" + producer.getUniqueName());
                continue;
            }

            if (log.isDebugEnabled()) log.debug("creating resource " + producer);
            try {
                producer.init();
            } catch (ResourceConfigurationException ex) {
                log.warn("unable to create resource with unique name " + producer.getUniqueName(), ex);
                producer.close();
                errorCount++;
            }

            resourcesByUniqueName.put(producer.getUniqueName(), producer);
        }

        return errorCount;
    }

    /**
     * Create a map using the configured resource name as the key and a List of PropertyPair objects as the value.
     * @param properties object to analyze.
     * @return the built map.
     */
    private Map buildConfigurationEntriesMap(Properties properties) {
        Map entries = new HashMap();
        Iterator it = properties.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();

            if (key.startsWith("resource.")) {
                String[] keyParts = key.split("\\.");
                if (keyParts.length < 3 || keyParts.length > 4) {
                    log.warn("ignoring invalid entry in configuration file: " + key);
                    continue;
                }
                String configuredName = keyParts[1];
                String propertyName = keyParts[2];
                if (keyParts.length == 4) {
                    propertyName += "." + keyParts[3];
                }

                List pairs = (List) entries.get(configuredName);
                if (pairs == null) {
                    pairs = new ArrayList();
                    entries.put(configuredName, pairs);
                }

                pairs.add(new PropertyPair(propertyName, value));
            }
        }
        return entries;
    }

    /**
     * Build a populated {@link XAResourceProducer} out of a list of property pairs and the config name.
     * @param configuredName index name of the config file.
     * @param propertyPairs the properties attached to this index.
     * @return a populated {@link XAResourceProducer}.
     * @throws ResourceConfigurationException if the {@link XAResourceProducer} cannot be built.
     */
    private XAResourceProducer buildXAResourceProducer(String configuredName, List propertyPairs) throws ResourceConfigurationException {
        String lastPropertyName = "className";
        try {
            XAResourceProducer producer = createBean(configuredName, propertyPairs);

            for (int i = 0; i < propertyPairs.size(); i++) {
                PropertyPair propertyPair = (PropertyPair) propertyPairs.get(i);
                lastPropertyName = propertyPair.getName();
                String propertyValue = propertyPair.getValue();

                PropertyUtils.setProperty(producer, lastPropertyName, propertyValue);
            }
            if (producer.getUniqueName() == null)
                throw new ResourceConfigurationException("missing mandatory property <uniqueName> for resource <" + configuredName + "> in resources configuration file");

            return producer;
        } catch (ResourceConfigurationException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new ResourceConfigurationException("cannot configure resource for configuration entries with name <" + configuredName + ">" + " - failing property is <" + lastPropertyName + ">", ex);
        }
    }

    /**
     * Create an unpopulated, uninitialized {@link XAResourceProducer} instance depending on the className value.
     * @param configuredName the properties configured name.
     * @param propertyPairs a list of {@link PropertyPair}s.
     * @return a {@link XAResourceProducer}.
     * @throws ClassNotFoundException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws IllegalAccessException if the {@link XAResourceProducer} cannot be instanciated.
     * @throws InstantiationException if the {@link XAResourceProducer} cannot be instanciated.
     */
    private XAResourceProducer createBean(String configuredName, List propertyPairs) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        for (int i = 0; i < propertyPairs.size(); i++) {
            PropertyPair propertyPair = (PropertyPair) propertyPairs.get(i);
            if (propertyPair.getName().equals("className")) {
                String className = propertyPair.getValue();
                XAResourceProducer producer = instanciate(className);
                if (producer == null)
                    throw new ResourceConfigurationException("property <className> " +
                            "for resource <" + configuredName + "> in resources configuration file " +
                            "must be the name of a class implementing either javax.sql.XADataSource or javax.jms.XAConnectionFactory");
                return producer;
            }
        }
        throw new ResourceConfigurationException("missing mandatory property <className> for resource <" + configuredName + "> in resources configuration file");
    }


    private class PropertyPair {
        private String name;
        private String value;

        public PropertyPair(String key, String value) {
            this.name = key;
            this.value = value;
        }

        public String getName() {
            return name;
        }

        public String getValue() {
            return value;
        }

        public String toString() {
            return name + "/" + value;
        }
    }

}

{'fraction_non_alphanumeric': 0.08863132124550532, 'fraction_numerical': 0.002142146737051488, 'mean_word_length': 2.373725642018325, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3303900', 'n_tokens_mistral': 6523, 'n_tokens_neox': 6213, 'n_words': 1883}