protected Ini parseConfig() {
        Ini ini = getIni();

        String[] configLocations = getConfigLocations();

        if (LOGGER.isWarnEnabled() && !CollectionUtils.isEmpty(ini)
                && configLocations != null && configLocations.length > 0) {
            LOGGER.warn("Explicit INI instance has been provided, but configuration locations have also been "
                            + "specified.  The {} implementation does not currently support multiple Ini config, but this may "
                            + "be supported in the future. Only the INI instance will be used for configuration.",
                    IniWebEnvironment.class.getName());
        }

        if (CollectionUtils.isEmpty(ini)) {
            LOGGER.debug("Checking any specified config locations.");
            ini = getSpecifiedIni(configLocations);
        }

        if (CollectionUtils.isEmpty(ini)) {
            LOGGER.debug("No INI instance or config locations specified.  Trying default config locations.");
            ini = getDefaultIni();
        }

        // Allow for integrations to provide default that will be merged other configuration.
        // to retain backwards compatibility this must be a different method then 'getDefaultIni()'
        ini = mergeIni(getFrameworkIni(), ini);

        if (CollectionUtils.isEmpty(ini)) {
            String msg = "Shiro INI configuration was either not found or discovered to be empty/unconfigured.";
            throw new ConfigurationException(msg);
        }
        return ini;
    }
Loads configuration {@link Ini} from {@link #getConfigLocations()} if set, otherwise falling back
to the {@link #getDefaultConfigLocations()}. Finally any Ini objects will be merged with the value returned
from {@link #getFrameworkIni()}

@return Ini configuration to be used by this Environment.
@since 1.4
web/src/main/java/org/apache/shiro/web/env/IniWebEnvironment.java