Setting manager class for reading and managing Settings.ini file of my program Setting manager class for reading and managing Settings.ini file
I have started a project creating Software Installer application for auto download and auto install software, similar how Ninite works. I have created SettingsManager.java class for reading and managing Settings.ini file of the program so the rest of the program can use it. This is just a draft of the class an it is not complete, but it is functional. I would like your opinions on the overall design and implementation of this kind of class.
The SettingsManager.java class
package com.zoran_jankov.software_installer.app;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.ini4j.Ini;

public class SettingsManager
{
    private static SettingsManager instance;
    
    private static final String SETTINGS_FILE_PATH = &quot;D:/Programing/Java/Software Installer/src/main/resources/Settings.ini&quot;;
    
    private Map&lt;Software, String&gt; localRepositories = new HashMap&lt;Software, String&gt;();
    private Map&lt;Software, String&gt; networkRepositories = new HashMap&lt;Software, String&gt;();
    private Map&lt;Software, String&gt; onlineRepositories = new HashMap&lt;Software, String&gt;();
    private Map&lt;Software, String&gt; arguments = new HashMap&lt;Software, String&gt;();
    
    private SettingsManager()
    {
        loadSettings();
    }
    
    public static SettingsManager getInstance()
    {
        if(instance == null)
        {
            instance = new SettingsManager();
        }
        return instance;
    }
    
    public void loadSettings()
    {
        Ini settings = null;
        
        try
        {
            settings = new Ini(new File(SETTINGS_FILE_PATH));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        
        localRepositories = getInstallerSettings(settings, &quot;Local Repositories&quot;);
            
        networkRepositories = getInstallerSettings(settings, &quot;Network Repositories&quot;);
                
        onlineRepositories = getInstallerSettings(settings, &quot;Online Repositories&quot;);
                
        arguments = getInstallerSettings(settings, &quot;Arguments&quot;);

    }
    
    private Map&lt;Software, String&gt; getInstallerSettings(Ini setttings, String sectionName)
    {
        Map&lt;Software, String&gt; list = new HashMap&lt;Software, String&gt;();
        
        for (Software installer : Software.values())
        {
            list.put(installer, setttings.get(sectionName, installer.name()));
        }
        
        return list;
    }
    
    public String getLocalRepository(Software software)
    {
        return localRepositories.get(software);
    }
    
    public String getNetworkRepository(Software software)
    {
        return networkRepositories.get(software);
    }
    
    public String getOnlineRepository(Software software)
    {
        return onlineRepositories.get(software);
    }
    
    public String getArguments(Software software)
    {
        return arguments.get(software);
    }
}

The Software.java enum
package com.zoran_jankov.software_installer.app;
public enum Software
{
    AIMP,
    CCleaner,
    DWGSee,
    Firefox,
    FoxitReader,
    ImgBurn,
    Java,
    LibreOffice,
    Notepad,
    Office365,
    OpenOffice,
    RocketChat,
    Skype,
    SpacePlanning,
    Speccy,
    Thunderbird,
    UltraVNC,
    VLC,
    ZabbixAgent,
    Zip;
}

The Settings.ini file
So you can better understand what is happening in the code.
Defualt Java style is to have the opening braces on the same line, but that's down to preferences. Just be consistent in your code.

private static final String SETTINGS_FILE_PATH = &quot;D:/Programing/Java/Software Installer/src/main/resources/Settings.ini&quot;;

You want to pass that path, somehow, as it is not portable.

public class SettingsManager
{
    private static SettingsManager instance;

    public static SettingsManager getInstance()
    {
        if(instance == null)
        {
            instance = new SettingsManager();
        }
        return instance;
    }
}

This is not thread-safe, in case you care about it. An obligatory number of threads could end up with their own, not-shared instances of the SettingsManager. There are three ways to prevent that:
The first is to use a static initializer:
public class SettingsManager
{
    private static SettingsManager instance;

    static
    {
        instance = new SettingsManager();
    }
}

Static initializers are guaranteed to be synchronized and will only be executed once the class is accessed.
The second option is to synchronize the whole method:
public class SettingsManager
{
    private static SettingsManager instance;

    public static synchronized SettingsManager getInstance()
    {
        if(instance == null)
        {
            instance = new SettingsManager();
        }
        return instance;
    }
}

This guarantees a single instance for everyone, but it means that an expensive lock is acquired for each access. &quot;Expensive&quot; in this case means &quot;compared to simply getting the value&quot;, in 99.99% of the cases you will not notice the performance difference to method #3.
The third method is to check twice whether the value is available, once &quot;cheap&quot;, and then synchronized:
public class SettingsManager
{
    private static SettingsManager instance;

    public static SettingsManager getInstance()
    {
        if(instance == null)
        {
            synchronized(SettingsManager.class)
            {
                if(instance == null)
                {
                    instance = new SettingsManager();
                }
            }
        }
        return instance;
    }
}

That skips the locking in most instances, except when required, namely if two threads try to access the instance for the first time.

private static final String SETTINGS_FILE_PATH = &quot;D:/Programing/Java/Software Installer/src/main/resources/Settings.ini&quot;;

You want to pass that path, somehow, as it is not portable in the slightest in this way.
Now, that leads to the problem that you only have one single, global instance, and if you pass the path you have to ask yourself the question what should be done when a second instance with a different path is requested. It might be better to have a single instance which you pass around in your application, or which you make globally accessible throughout your application, and not through the class level of this class.

        Ini settings = null;
        
        try
        {
            settings = new Ini(new File(SETTINGS_FILE_PATH));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

You most likely want to re-throw that exception, or let it propagate freely by letting loadSettings throw IOException. Silently swallowing exceptions might lead to a really bad headache when debugging problems.

Map&lt;Software, String&gt; list = new HashMap&lt;Software, String&gt;();

That's not a list, that's a map. Naming like that is confusing. Also, in Java 8+ you can omit the types in the constructor, as they are derived from the declaration:
Map&lt;Software, String&gt; list = new HashMap&lt;&gt;();


public enum Software
{
    AIMP,
    CCleaner,

Java convention is that enum members are considered constants, therefor should be UPPER_SNAKE_CASE.

Now, what you don't want is that Software enum, that should be configuration that you read, too, because that allows easier maintenance and extension of the software. Overall, your ini format seems not suited for what you want, it looks more like you want to invert the format:
[AIMP]
Local Repository=...
Network Repository=...
Online Repository=...
Arguments=...

[CCleaner]
Local Repository=...
Network Repository=...
Online Repository=...
Arguments=...

Because with that in place, you can kill off Software completely and make your application driven by configuration. You simply read the ini file and display the list of software that is configured instead of having it hard-coded.