eu.eidas.auth.commons.EIDASUtil.java Source code

Java tutorial

Introduction

Here is the source code for eu.eidas.auth.commons.EIDASUtil.java

Source

/*
 * This work is Open Source and licensed by the European Commission under the
 * conditions of the European Public License v1.1
 *
 * (http://www.osor.eu/eupl/european-union-public-licence-eupl-v.1.1);
 *
 * any use of this file implies acceptance of the conditions of this license.
 * 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 eu.eidas.auth.commons;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.eidas.auth.commons.exceptions.InternalErrorEIDASException;
import eu.eidas.util.Preconditions;

/**
 * Static helper methods.
 *
 * @deprecated This class has more than one responsibility and relies on a mutable static state with is setup in an
 * awkward way.
 */
@SuppressWarnings("ConstantConditions")
@Deprecated
public enum EIDASUtil {

    /**
     * Effective Java, 2nd Ed.: Item 3: Enforce the singleton property with an enum type.
     */
    INSTANCE;

    /**
     * Logger object.
     */
    private static final Logger LOG = LoggerFactory.getLogger(EIDASUtil.class);

    private static final Pattern SEMI_COLON_SEPARATOR_PATTERN = Pattern.compile(";");

    /**
     * Path and name of the EIDAS properties file.
     */
    private static final String EIDAS_UTIL_PROPERTIES = "eidasUtil.properties";

    /**
     * Path and name of the EIDAS configuration indirection properties file.
     */
    private static final String CONFIG_LOCATION_PROPERTIES = "configlocation.properties";

    @SuppressWarnings("CollectionDeclaredAsConcreteClass")
    @Nonnull
    static ImmutableMap<String, String> immutableMap(@Nullable Properties properties) {
        if (null == properties || properties.isEmpty()) {
            return ImmutableMap.of();
        }
        return Maps.fromProperties(properties);
    }

    @Nonnull
    static Properties toProperties(@Nonnull ImmutableMap<String, String> immutableMap) {
        Properties properties = new Properties();
        //noinspection UseOfPropertiesAsHashtable
        properties.putAll(immutableMap);
        return properties;
    }

    /**
     * Configurations object.
     */
    private final AtomicReference<ImmutableMap<String, String>> propertiesRef;

    /**
     * Private constructor. Prevents the class from being instantiated.
     */
    EIDASUtil() {
        propertiesRef = new AtomicReference<ImmutableMap<String, String>>(ImmutableMap.<String, String>of());
    }

    /**
     * Sets the properties.
     *
     * @param properties The properties to set.
     * @return the singleton instance (same as {@link #INSTANCE}).
     * @deprecated This method is badly named, it only sets the properties to a new reference. Use {@link
     * #setConfigs(Properties)} instead.
     */
    @Deprecated
    public static EIDASUtil createInstance(final Properties properties) {
        setProperties(immutableMap(properties));
        return INSTANCE;
    }

    /**
     * Returns a new copy of the Properties.
     *
     * @return a new copy of the Properties.
     * @deprecated Use {@link #getProperties()} instead.
     */
    @Nonnull
    @Deprecated
    public Properties getConfigs() {
        return toProperties(getProperties());
    }

    /**
     * Returns the current properties.
     *
     * @return the current properties.
     * @since 1.1
     */
    @Nonnull
    public ImmutableMap<String, String> getProperties() {
        return propertiesRef.get();
    }

    /**
     * Setter for the configuration.
     *
     * @param properties The new properties.
     */
    public static void setProperties(@Nonnull Map<String, String> properties) {
        Preconditions.checkNotNull(properties, "properties");
        setProperties(ImmutableMap.copyOf(properties));
    }

    /**
     * Setter for the Properties which loads the default file if the given argument is {@code null}.
     *
     * @param properties The new properties value. If this argument is {@code null}, then the default file is loaded
     * ({@link #EIDAS_UTIL_PROPERTIES}).
     */
    public static void setConfigs(@Nullable Properties properties) {
        Properties newProperties = properties;
        if (null == newProperties) {
            newProperties = loadConfigs(EIDAS_UTIL_PROPERTIES);
        }
        setProperties(immutableMap(newProperties));
    }

    private static void setProperties(@Nonnull ImmutableMap<String, String> properties) {
        Preconditions.checkNotNull(properties, "properties");
        INSTANCE.propertiesRef.set(properties);
    }

    /**
     * Returns the identifier of some configuration given a set of configurations and the corresponding configuration
     * key.
     *
     * @param configKey The key that IDs some configuration.
     * @return The configuration String value.
     */
    @Nullable
    public static String getConfig(@Nullable String configKey) {
        Preconditions.checkNotNull(configKey, "configKey");
        ImmutableMap<String, String> properties = INSTANCE.getProperties();
        final String propertyValue;
        if (properties.isEmpty()) {
            LOG.warn("BUSINESS EXCEPTION : Configs not loaded - property-Key value is null or empty {} ",
                    configKey);
            propertyValue = configKey;
        } else {
            propertyValue = properties.get(configKey);
            if (StringUtils.isEmpty(propertyValue)) {
                LOG.warn("BUSINESS EXCEPTION : Invalid property-Key value is null or empty {}", configKey);
            }
        }
        return propertyValue;
    }

    /**
     * Gets the Eidas error code in the error message if exists!
     *
     * @param errorMessage The message to get the error code if exists;
     * @return the error code if exists. Returns null otherwise.
     */
    public static String getEidasErrorCode(final String errorMessage) {
        if (StringUtils.isNotBlank(errorMessage)
                && errorMessage.indexOf(EIDASValues.ERROR_MESSAGE_SEP.toString()) >= 0) {
            final String[] msgSplitted = errorMessage.split(EIDASValues.ERROR_MESSAGE_SEP.toString());
            if (msgSplitted.length == 2 && StringUtils.isNumeric(msgSplitted[0])) {
                return msgSplitted[0];
            }
        }
        return null;
    }

    /**
     * Gets the Eidas error message in the saml message if exists!
     *
     * @param errorMessage The message to get in the saml message if exists;
     * @return the error message if exists. Returns the original message otherwise.
     */
    public static String getEidasErrorMessage(final String errorMessage) {
        if (StringUtils.isNotBlank(errorMessage)
                && errorMessage.indexOf(EIDASValues.ERROR_MESSAGE_SEP.toString()) >= 0) {
            final String[] msgSplitted = errorMessage.split(EIDASValues.ERROR_MESSAGE_SEP.toString());
            if (msgSplitted.length == 2 && StringUtils.isNumeric(msgSplitted[0])) {
                return msgSplitted[1];
            }
        }
        return errorMessage;
    }

    private static final String CLASSPATH_PREFIX = "classpath:/";

    private static final String FILE_PREFIX = "file:";

    /**
     * Loads the configuration file pointed by the given path.
     *
     * @param path Path to the input file
     * @param logError Whether to log the error or to silently ignore it
     * @return property The loaded Properties
     * @throws InternalErrorEIDASException if the configuration file could not be loaded.
     */
    public static Properties loadConfigs(String path, boolean logError) {
        Properties properties = new Properties();
        InputStream is = null;
        try {
            is = EIDASUtil.class.getClassLoader().getResourceAsStream(path);
            if (is == null) {
                is = indirectedProps(path);
            }
            if (is != null) {
                properties.load(is);
            }
        } catch (IOException e) {
            if (logError) {
                LOG.error("An error occurs when trying to load configuration file: " + path, e);
                throw new InternalErrorEIDASException("5", "Internal server error on loading configurations", e);
            }
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    if (logError) {
                        LOG.error("An error occurred when trying to close resource stream: ", e);
                    }
                    // call ex.addSuppressed(e); when Java 7+ or better use the try with resource
                }
            }
        }
        return properties;
    }

    private static InputStream indirectedProps(String path) throws IOException {
        Properties indirection = EIDASUtil.loadConfigs(CONFIG_LOCATION_PROPERTIES);
        String location = indirection.getProperty(path);
        InputStream is = null;
        if (location != null) {
            if (location.startsWith(CLASSPATH_PREFIX)) {
                is = EIDASUtil.class.getClassLoader()
                        .getResourceAsStream(location.substring(CLASSPATH_PREFIX.length()));
            } else if (location.startsWith(FILE_PREFIX)) {
                is = new FileInputStream(location.substring(FILE_PREFIX.length()));
            }
        }
        return is;
    }

    public static Properties loadConfigs(String path) {
        return loadConfigs(path, true);
    }

    /**
     * @param values a string containing several chunks separated by ;
     * @return a set of chunks extracted from values
     */
    @Nonnull
    public static Set<String> parseSemicolonSeparatedList(@Nullable String values) {
        Set<String> result = new HashSet<String>();
        if (!StringUtils.isEmpty(values)) {
            String[] valuesArr = SEMI_COLON_SEPARATOR_PATTERN.split(values);
            if (valuesArr != null) {
                for (String value : valuesArr) {
                    value = value.trim();
                    if (!StringUtils.isEmpty(value)) {
                        result.add(value);
                    }
                }
            }
        }
        return result;
    }
}