001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.core;
020
021import java.io.BufferedInputStream;
022import java.io.FileInputStream;
023import java.io.IOException;
024import java.io.Serializable;
025import java.util.*;
026import java.util.stream.IntStream;
027
028/**
029 * @author apr@cs.com.uy
030 * @version $Id$
031 * @since jPOS 1.1
032 */
033public class SimpleConfiguration implements Configuration, Serializable {
034    private Properties props;
035
036    public SimpleConfiguration () {
037        props = new Properties();
038    }
039    public SimpleConfiguration (Properties props) {
040        this.props = props;
041    }
042    public SimpleConfiguration (String filename)
043        throws IOException
044    {
045        props = new Properties();
046        load (filename);
047    }
048
049    /**
050     * Returns the value of the configuration property named <tt>name</tt>, or the default value <tt>def</tt>.
051     *
052     * If the property value has the format <code>${xxx}</code> then its value is taken from a system property
053     * if it exists, or an environment variable. System property takes priority over environment variable.
054     *
055     * If the format is <code>$sys{...}</code> we read only a system property.
056     * if the format is <code>$env{...}</code> only an environment variable is used.
057     *
058     * @param name The configuration property key name.
059     * @param def  The default value.
060     * @return  The value stored under <tt>name</tt>,
061     *          or <tt>def</tt> if there's no configuration property under the given <tt>name</tt>.
062     */
063    public String get (String name, String def) {
064        Object obj = props.get (name);
065        if (obj instanceof String[]) {
066            String[] arr= (String[]) obj;
067            obj = arr.length > 0 ? arr[0] : null;
068        } else if (obj instanceof List) {
069            List l = (List) obj;
070            obj = l.size() > 0 ? l.get(0) : null;
071        }
072        return (obj instanceof String) ? Environment.get((String) obj, def) : def;
073    }
074    public String[] getAll (String name) {
075        String[] ret;
076        Object obj = props.get (name);
077        if (obj instanceof String[]) {
078            ret = (String[]) obj;
079        } else if (obj instanceof String) {
080            ret = new String[1];
081            ret[0] = (String) obj;
082        } else
083            ret = new String[0];
084
085        Environment env = Environment.getEnvironment();
086        IntStream.range(0, ret.length).forEachOrdered(i -> ret[i] = env.getProperty(ret[i]));
087        return Arrays.stream(ret).filter(Objects::nonNull).toArray(String[]::new);
088    }
089    public int[] getInts (String name) {
090        String[] ss = getAll (name);
091        int[] ii = new int[ss.length];
092        for (int i=0; i<ss.length; i++)
093            ii[i] = Integer.parseInt(ss[i].trim());
094        return ii;
095    }
096    public long[] getLongs (String name) {
097        String[] ss = getAll (name);
098        long[] ll = new long[ss.length];
099        for (int i=0; i<ss.length; i++)
100            ll[i] = Long.parseLong(ss[i].trim());
101        return ll;
102    }
103    public double[] getDoubles (String name) {
104        String[] ss = getAll (name);
105        double[] dd = new double[ss.length];
106        for (int i=0; i<ss.length; i++)
107            dd[i] = Double.valueOf(ss[i].trim());
108        return dd;
109    }
110    public boolean[] getBooleans (String name) {
111        String[] ss = getAll (name);
112        boolean[] bb = new boolean[ss.length];
113        for (int i=0; i<ss.length; i++)
114            bb[i] = ss[i].equalsIgnoreCase("true") || ss[i].equalsIgnoreCase("yes");
115        return bb;
116    }
117    public String get (String name) {
118        return get(name, "");
119    }
120    public int getInt (String name) {
121        return Integer.parseInt(get(name, "0").trim());
122    }
123    public int getInt (String name, int def) {
124        return Integer.parseInt(get(name, Integer.toString(def)).trim());
125    }
126    public long getLong (String name) {
127        return Long.parseLong(get(name, "0").trim());
128    }
129    public long getLong (String name, long def) {
130        return Long.parseLong(get(name, Long.toString(def)).trim());
131    }
132    public double getDouble(String name) {
133        return Double.valueOf(get(name, "0.00").trim());
134    }
135    public double getDouble(String name, double def) {
136        return Double.valueOf(get(name, Double.toString(def)).trim());
137    }
138    public boolean getBoolean (String name) {
139        String v = get (name, "false").trim();
140        return v.equalsIgnoreCase("true") || v.equalsIgnoreCase("yes");
141    }
142    public boolean getBoolean (String name, boolean def) {
143        String v = get (name);
144        return v.length() == 0 ? def :
145                v.equalsIgnoreCase("true") || v.equalsIgnoreCase("yes");
146    }
147    public void load(String filename) 
148        throws IOException
149    {
150        FileInputStream fis = new FileInputStream(filename);
151        props.load(new BufferedInputStream(fis));
152        fis.close();
153    }
154    public synchronized void put (String name, Object value) {
155        props.put (name, value);
156    }
157    @Override
158    public Set<String> keySet() {
159        return props.stringPropertyNames();
160    }
161
162    @Override
163    public boolean equals(Object o) {
164        if (this == o) return true;
165        if (o == null || getClass() != o.getClass()) return false;
166        SimpleConfiguration that = (SimpleConfiguration) o;
167        return Objects.equals(props, that.props);
168    }
169
170    @Override
171    public int hashCode() {
172        return Objects.hash(props);
173    }
174
175    @Override
176    public String toString() {
177        return "SimpleConfiguration{" +
178          "props=" + props +
179          '}';
180    }
181
182    private static final long serialVersionUID = -6361797037366246968L;
183}