/*
 *  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.daemon.support;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;
import java.text.ParseException;

/**
 * Used by jsvc for Daemon configuration.
 * <p>
 * Configuration is read from properties file.
 * If no properties file is given the {@code daemon.properties}
 * is used from the current directory.
 * </p>
 * <p>
 * The properties file can have property values expanded at runtime
 * by using System properties or execution environment. The part
 * of the property value between {@code ${} and {@code }}
 * will be used as System property or environment key. If found then
 * the entire {@code ${foo}} will be replaced by the value of
 * either system property or environment variable named {@code foo}.
 * </p>
 * <p>
 * If no variable is found the {@code ${foo}}  will be passed as is.
 * In case of {@code $${foo}} this will be unescaped and resulting
 * value will be {@code ${foo}}.
 * </p>
 *
 */
public final class DaemonConfiguration
{
    /**
     * Default configuration file name.
     */
    protected final static String DEFAULT_CONFIG        = "daemon.properties";
    /**
     * Property prefix
     */
    protected final static String PREFIX                = "daemon.";
    private   final static String BTOKEN                = "${";
    private   final static String ETOKEN                = "}";


    private final Properties configurationProperties;
    private final Properties systemProperties;

    /**
     * An empty immutable {@code String} array.
     */
    static final String[] EMPTY_STRING_ARRAY = {};

    /**
     * Default constructor
     */
    public DaemonConfiguration()
    {
        configurationProperties = new Properties();
        systemProperties        = System.getProperties();
    }

    /**
     * Loads the configuration properties file.
     *
     * @param fileName The properties file to load.
     * @return {@code true} if the file was loaded.
     */
    public boolean load(String fileName)
    {
        boolean ok = false;
        FileInputStream inputStream = null;
        try {
            if (fileName == null) {
                fileName = DEFAULT_CONFIG;
            }
            inputStream = new FileInputStream(fileName);
            configurationProperties.clear();
            configurationProperties.load(inputStream);
            ok = true;
        }
        catch (final IOException ex) {
            // Error reading properties file
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (final IOException ex) {
                // ignore
            }
        }
        return ok;
    }

    private String expandProperty(final String propValue)
        throws ParseException
    {
        final StringBuilder expanded;
        int btoken;
        int ctoken = 0;

        if (propValue == null) {
            return null;
        }
        expanded = new StringBuilder();
        btoken   = propValue.indexOf(BTOKEN);
        while (btoken != -1) {
            if (btoken > 0 && propValue.charAt(btoken - 1) == BTOKEN.charAt(0)) {
                // Skip and unquote.
                expanded.append(propValue.substring(ctoken, btoken));
                ctoken = btoken + 1;
                btoken = propValue.indexOf(BTOKEN, btoken + BTOKEN.length());
                continue;
            }
            final int etoken = propValue.indexOf(ETOKEN, btoken);
            if (etoken == -1) {
                // We have "${" without "}"
                throw new ParseException("Error while looking for teminating '" +
                                         ETOKEN + "'", btoken);
            }
            final String variable = propValue.substring(btoken + BTOKEN.length(), etoken);
            String sysvalue = systemProperties.getProperty(variable);
            if (sysvalue == null) {
                // Try with the environment if there was no
                // property by that name.
                sysvalue = System.getenv(variable);
            }
            if (sysvalue != null) {
                final String strtoken = propValue.substring(ctoken, btoken);
                expanded.append(strtoken);
                expanded.append(sysvalue);
                ctoken = etoken + ETOKEN.length();
            }
            btoken = propValue.indexOf(BTOKEN, etoken + ETOKEN.length());
        }
        // Add what's left.
        expanded.append(propValue.substring(ctoken));
        return expanded.toString();
    }

    /**
     * Gets the configuration property.
     *
     * @param name The name of the property to get.
     *
     * @throws ParseException if the property is wrongly formatted.
     *
     * @return  Configuration property including any expansion/replacement
     */
    public String getProperty(final String name)
        throws ParseException
    {
        if (name == null) {
            return null;
        }
        return expandProperty(configurationProperties.getProperty(PREFIX + name));
    }

    /**
     * Gets the configuration property array.
     * <p>
     * Property array is constructed form the list of properties
     * which end with {@code [index]}
     * </p>
     * <pre>
     * daemon.arg[0] = argument 1
     * daemon.arg[1] = argument 2
     * daemon.arg[2] = argument 3
     * </pre>
     * @param name The name of the property array to get.
     *
     * @throws ParseException if the property is wrongly formatted.
     *
     * @return  Configuration property array including any expansion/replacement
     */
    public String[] getPropertyArray(final String name)
        throws ParseException
    {
        final ArrayList<String> list = new ArrayList<>();
        String    args;

        // Load daemon.arg[0] ... daemon.arg[n] into the String array.
        //
        while ((args = getProperty(name + "[" + list.size() + "]")) != null) {
            list.add(args);
        }
        return list.toArray(EMPTY_STRING_ARRAY);
    }
}


@@ -912,16 +912,44 @@
 eption;%0A
+import java.io.InputStream;%0A
 import j
@@ -2895,98 +2895,8 @@
   %7B%0A
-        boolean ok = false;%0A        FileInputStream inputStream = null;%0A        try %7B%0A    
     
@@ -2935,20 +2935,16 @@
         
- 
-   
 fileName
@@ -2962,36 +2962,32 @@
 CONFIG;%0A        
-    
 %7D%0A            in
@@ -2972,36 +2972,58 @@
       %7D%0A        
+%0A    
     
+try (InputStream 
 inputStream = ne
@@ -3049,17 +3049,19 @@
 ileName)
-;
+) %7B
 %0A       
@@ -3169,12 +3169,14 @@
     
-ok =
+return
  tru
@@ -3187,24 +3187,16 @@
        %7D
-%0A       
  catch (
@@ -3276,253 +3276,35 @@
     
-%7D finally %7B%0A            try %7B%0A                if (inputStream != null) %7B%0A                    inputStream.close();%0A                %7D%0A            %7D catch (final IOException ex) %7B%0A                // ignore%0A            %7D%0A        %7D%0A        return ok;
+    return false;%0A        %7D
 %0A   

Use try-with-resources