001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.property;
017
018import static com.google.common.base.Preconditions.checkArgument;
019import static org.kuali.common.util.base.Precondition.checkNotNull;
020
021import java.io.InputStream;
022import java.io.Reader;
023import java.util.Collection;
024import java.util.Map;
025import java.util.Properties;
026import java.util.Set;
027
028import com.google.common.collect.ImmutableList;
029import com.google.common.collect.ImmutableSet;
030
031/**
032 * Immutable version of <code>java.util.Properties</code> that is guaranteed to only contain string keys and values
033 */
034public final class ImmutableProperties extends Properties {
035
036    private static final long serialVersionUID = 0L;
037    private static final String UOE_MSG = "Immutable properties cannot be changed";
038    private static final Properties EMPTY = copyOf(new Properties());
039
040    public ImmutableProperties(Properties mutable) {
041        checkNotNull(mutable, "mutable");
042
043        // Prevent anything from changing original until we are done
044        synchronized (mutable) {
045
046            // Extract only those keys where both the key and its corresponding value are strings
047            Set<String> keys = mutable.stringPropertyNames();
048
049            // If the sizes are different, original contains at least one key or value that is not a string
050            checkArgument(keys.size() == mutable.size(), "Immutable properties only support strings");
051
052            // Copy every key/value pair from original - can't use putAll() since it calls put() which is now disabled
053            for (String key : keys) {
054                super.put(key, mutable.getProperty(key));
055            }
056        }
057    }
058
059    public static Properties of(String name, String value) {
060        Properties props = new Properties();
061        props.setProperty(name, value);
062        return copyOf(props);
063    }
064
065    public static Properties of() {
066        return EMPTY;
067    }
068
069    /**
070     * Create and return a new immutable properties object identical to the one passed in. If <code>properties</code> is already immutable, no new object is created, the
071     * <code>properties</code> object passed in as a method argument is what is returned.
072     *
073     * @throws NullPointerException
074     *             if {@code properties} is null
075     *
076     * @deprecated use copyOf(Properties) instead
077     */
078    @Deprecated
079    public static Properties of(Properties properties) {
080        return copyOf(properties);
081    }
082
083    /**
084     * Create and return a new immutable properties object identical to the one passed in. If <code>properties</code> is already immutable, no new object is created, the
085     * <code>properties</code> object passed in as a method argument is what is returned.
086     *
087     * @throws NullPointerException
088     *             if {@code properties} is null
089     */
090    public static ImmutableProperties copyOf(Properties properties) {
091        checkNotNull(properties, "properties");
092        if (properties instanceof ImmutableProperties) {
093            return (ImmutableProperties) properties;
094        } else {
095            return new ImmutableProperties(properties);
096        }
097    }
098
099    public static ImmutableProperties copyOf(Map<String, String> map) {
100        checkNotNull(map, "map");
101        Properties properties = new Properties();
102        for (String key : map.keySet()) {
103            properties.setProperty(key, map.get(key));
104        }
105        return copyOf(properties);
106    }
107
108    /**
109     * @deprecated Not supported for immutable properties
110     */
111    @Deprecated
112    @Override
113    public Object setProperty(String key, String value) {
114        throw new UnsupportedOperationException(UOE_MSG);
115    }
116
117    /**
118     * @deprecated Not supported for immutable properties
119     */
120    @Deprecated
121    @Override
122    public void load(Reader reader) {
123        throw new UnsupportedOperationException(UOE_MSG);
124    }
125
126    /**
127     * @deprecated Not supported for immutable properties
128     */
129    @Deprecated
130    @Override
131    public void load(InputStream inStream) {
132        throw new UnsupportedOperationException(UOE_MSG);
133    }
134
135    /**
136     * @deprecated Not supported for immutable properties
137     */
138    @Deprecated
139    @Override
140    public void loadFromXML(InputStream in) {
141        throw new UnsupportedOperationException(UOE_MSG);
142    }
143
144    /**
145     * @deprecated Not supported for immutable properties
146     */
147    @Deprecated
148    @Override
149    public Object put(Object key, Object value) {
150        throw new UnsupportedOperationException(UOE_MSG);
151    }
152
153    /**
154     * @deprecated Not supported for immutable properties
155     */
156    @Deprecated
157    @Override
158    public Object remove(Object key) {
159        throw new UnsupportedOperationException(UOE_MSG);
160    }
161
162    /**
163     * @deprecated Not supported for immutable properties
164     */
165    @Deprecated
166    @Override
167    public void putAll(Map<? extends Object, ? extends Object> t) {
168        throw new UnsupportedOperationException(UOE_MSG);
169    }
170
171    /**
172     * @deprecated Not supported for immutable properties
173     */
174    @Deprecated
175    @Override
176    public void clear() {
177        throw new UnsupportedOperationException(UOE_MSG);
178    }
179
180    @Override
181    public Set<Object> keySet() {
182        return ImmutableSet.copyOf(super.keySet());
183    }
184
185    @Override
186    public Set<java.util.Map.Entry<Object, Object>> entrySet() {
187        return ImmutableSet.copyOf(super.entrySet());
188    }
189
190    @Override
191    public Collection<Object> values() {
192        return ImmutableList.copyOf(super.values());
193    }
194
195}