zcommon/src/main/java/org/zkoss/lang/Library.java

Summary

Maintainability
A
2 hrs
Test Coverage
/* Library.java

    Purpose:
        
    Description:
        
    History:
        Fri Aug  1 09:06:36     2008, Created by tomyeh

Copyright (C) 2008 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
    This program is distributed under LGPL Version 2.1 in the hope that
    it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.lang;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Represent the scope of ZK libraries.
 * Unlike {@link System}, the scope of {@link Library} depends how
 * ZK libraries are installed.
 * If they are installed in WEB-INF/lib of a ZK application,
 * the scope is the application. In other words, the library properties
 * ({@link #setProperty}) are shared by the application only.
 *
 * <p>On the other hand, if ZK libraries are installed in a folder
 * shared by all applications, the library properties are shared
 * by all applications.
 *
 * @author tomyeh
 * @since 3.0.7
 */
public class Library {
    private static final Logger log = LoggerFactory.getLogger(Library.class);
    //ZK-3823: Using the ConcurrentHashMap to substitute synchronized HashMap can avoid the thread lock issue.
    //Enhance the performance of the code. 
    private static final Map<String, List<String>> _props = new ConcurrentHashMap<String, List<String>>();

    private Library() {}

    /** Returns the library property indicated by the specified key.
     * If no such library property, this method will call
     * {@link System#getProperty} to look for a system property.
     *
     * <p>The library property is shared by Java codes that access
     * the same set of ZK libraries, since it is actually
     * a static member of this class. Thus, if ZK libraries (including
     * this class) are installed in WEB-INF/lib of an application,
     * the library properties are accessible only in the application.
     *
     * <p>Note: unlike {@link System#getProperty}, this method won't
     * throw SecurityException.
     *
     * @return the string value of the library property, or the system
     * property, or null if no such property.
     * @see #setProperty
     */
    public static String getProperty(String key) {
        final String v;
        List<String> valList = _props.get(key);
        if (valList != null && valList.size() > 0)
            v = valList.get(0);
        else
            v = null;
        try {
            //Unlike System.getProperty, we make the inocation as safe as possible
            return v != null || key == null || key.length() == 0 ?
                v: System.getProperty(key);
        } catch (SecurityException ex) {
            return null;
        }
    }
    /** Returns the library property indicated by the specified key.
     * If no such library property, this method will call
     * {@link System#getProperty} to look for a system property.
     *
     * <p>Note: unlike {@link System#getProperty}, this method won't
     * throw SecurityException.
     *
     * @param key the name of the library property
     * @param def a default value.
     * @exception NullPointerException if key is null
     * @exception IllegalArgumentException if key is empty
     */
    public static String getProperty(String key, String def) {
        final String v;
        List<String> valList = _props.get(key);
        if (valList != null && valList.size() > 0)
            v = valList.get(0);
        else
            v = null;
        try {
            return v != null ? v: System.getProperty(key, def);
        } catch (SecurityException ex) {
            return def;
        }
    }
    /** Sets the library property indicated by the specified key.
     * @see #getProperty
     * @exception NullPointerException if key is null
     * @exception IllegalArgumentException if key is empty
     * @return the previous value of the library property, or null if
     * it did not have one.
     */
    public static String setProperty(String key, String value) {
        if (key == null) throw new NullPointerException();
        if (key.length() == 0) throw new IllegalArgumentException();

        List<String> vals = new LinkedList<String>();
        vals.add(value);
        List<String> prev = _props.put(key, vals);
        return prev != null && prev.size() > 0 ? prev.get(0) : null;
    }

    /** Parses the property value to an integer.
     * If the specified value is not an integer, the default value is returned
     * (and a warning is logged).
     * @param defVal the default value
     * @since 3.6.1
     */
    public static int getIntProperty(String key, int defVal) {
        final String val = getProperty(key);
        if (val != null) {
            try {
                return Integer.parseInt(val);
            } catch (Throwable t) {
                log.warn("Failed to parse " + key + ": not an integer, " + val);
            }
        }
        return defVal;
    }

    /** Add a library property indicated by the specified key.
     * @see #getProperties
     * @exception NullPointerException if key is null
     * @exception IllegalArgumentException if key is empty
     * @return the previous value of the library properties, or null if
     * it did not have any.
     */
    public static List<String> addProperty(String key, String value) {
        if (key == null) throw new NullPointerException();
        if (key.length() == 0) throw new IllegalArgumentException();

        synchronized (_props) {
            List<String> old = _props.get(key);
            if (old == null)
                old = new LinkedList<String>();
            old.add(value);
            return _props.put(key, old);
        }
    }

    /** Add library properties indicated by the specified key.
     * @see #getProperties
     * @exception NullPointerException if key is null
     * @exception IllegalArgumentException if key is empty
     * @return the previous value of the library properties, or null if
     * it did not have any.
     */
    public static List<String> addProperties(String key, List<String> values) {
        if (key == null) throw new NullPointerException();
        if (key.length() == 0) throw new IllegalArgumentException();

        synchronized (_props) {
            List<String> old = _props.get(key);
            if (old == null)
                old = new LinkedList<String>();
            old.addAll(values);
            return _props.put(key, old);
        }
    }

    /** Sets the library properties indicated by the specified key.
     * @see #getProperties
     * @exception NullPointerException if key is null
     * @exception IllegalArgumentException if key is empty
     * @return the previous value of the library properties, or null if
     * it did not have any.
     */
    public static List<String> setProperties(String key, List<String> values) {
        if (key == null) throw new NullPointerException();
        if (key.length() == 0) throw new IllegalArgumentException();

        return _props.put(key, new LinkedList<String>(values));
    }

    /** Returns the library properties indicated by the specified key.
     *
     * <p>The library properties is shared by Java codes that access
     * the same set of ZK libraries, since it is actually
     * a static member of this class. Thus, if ZK libraries (including
     * this class) are installed in WEB-INF/lib of an application,
     * the library properties are accessible only in the application.
     *
     * @return the List of values of the library properties,
     * or null if no such property.
     * @see #setProperties
     */
    public static List<String> getProperties(String key) {
        return  _props.get(key);
    }
}