/* * 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.wicket.util.value; import java.io.Serializable; import java.util.Collection; import java.util.Map; import java.util.Set; import org.apache.wicket.util.string.StringValue; import org.apache.wicket.util.string.StringValueConversionException; import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.time.Time; /** * An implementation of <code>IValueMap</code> that makes a copy when a caller tries to change an * immutable <code>Map</code>. That is, the <code>Map</code> may or may not be immutable, but if it * is, a copy is made. * * @author Johan Compagner * @author Doug Donohoe * @since 1.2.6 */ public class CopyOnWriteValueMap implements IValueMap, Serializable { private static final long serialVersionUID = 1L; /** the wrapped <code>IValueMap</code> */ private IValueMap wrapped; /** * Constructor. * * @param wrapped * the wrapped <code>IValueMap</code> */ public CopyOnWriteValueMap(final IValueMap wrapped) { this.wrapped = wrapped; } /** * @see java.util.Map#clear() */ @Override public void clear() { checkAndCopy(); wrapped.clear(); } /** * Checks if this <code>IValueMap</code> is immutable. If it is, this method makes a new * <code>IValueMap</code> using the <code>ValueMap</code> copy constructor, and sets it to be * this <code>CopyOnWriteValueMap</code>. */ private void checkAndCopy() { if (wrapped.isImmutable()) { wrapped = new ValueMap(wrapped); } } /** * @see java.util.Map#containsKey(Object) */ @Override public boolean containsKey(final Object key) { return wrapped.containsKey(key); } /** * @see java.util.Map#containsValue(Object) */ @Override public boolean containsValue(final Object value) { return wrapped.containsValue(value); } /** * @see java.util.Map#entrySet() */ @Override public Set<Entry<String, Object>> entrySet() { checkAndCopy(); return wrapped.entrySet(); } /** * @see java.util.Map#equals(Object) */ @Override public boolean equals(final Object o) { return wrapped.equals(o); } @Override public int hashCode() { return wrapped.hashCode(); } /** * @see java.util.Map#get(Object) */ @Override public Object get(final Object key) { return wrapped.get(key); } /** * @see IValueMap#getBoolean(String) */ @Override public boolean getBoolean(final String key) throws StringValueConversionException { return wrapped.getBoolean(key); } /** * @see IValueMap#getCharSequence(String) */ @Override public CharSequence getCharSequence(final String key) { return wrapped.getCharSequence(key); } /** * @see IValueMap#getDouble(String) */ @Override public double getDouble(final String key) throws StringValueConversionException { return wrapped.getDouble(key); } /** * @see IValueMap#getDouble(String, double) */ @Override public double getDouble(final String key, final double defaultValue) { return wrapped.getDouble(key, defaultValue); } /** * @see IValueMap#getDuration(String) */ @Override public Duration getDuration(final String key) throws StringValueConversionException { return wrapped.getDuration(key); } /** * @see IValueMap#getInt(String, int) */ @Override public int getInt(final String key, final int defaultValue) { return wrapped.getInt(key, defaultValue); } /** * @see IValueMap#getInt(String) */ @Override public int getInt(final String key) throws StringValueConversionException { return wrapped.getInt(key); } /** * @see IValueMap#getKey(String) */ @Override public String getKey(final String key) { return wrapped.getKey(key); } /** * @see IValueMap#getLong(String, long) */ @Override public long getLong(final String key, final long defaultValue) { return wrapped.getLong(key, defaultValue); } /** * @see IValueMap#getLong(String) */ @Override public long getLong(final String key) throws StringValueConversionException { return wrapped.getLong(key); } /** * @see IValueMap#getString(String, String) */ @Override public String getString(final String key, final String defaultValue) { return wrapped.getString(key, defaultValue); } /** * @see IValueMap#getString(String) */ @Override public String getString(final String key) { return wrapped.getString(key); } /** * @see IValueMap#getStringArray(String) */ @Override public String[] getStringArray(final String key) { return wrapped.getStringArray(key); } /** * @see IValueMap#getStringValue(String) */ @Override public StringValue getStringValue(final String key) { return wrapped.getStringValue(key); } /** * @see IValueMap#getTime(String) */ @Override public Time getTime(final String key) throws StringValueConversionException { return wrapped.getTime(key); } /** * @see java.util.Map#isEmpty() */ @Override public boolean isEmpty() { return wrapped.isEmpty(); } /** * @see IValueMap#isImmutable() */ @Override public boolean isImmutable() { return false; } /** * @see java.util.Map#keySet() */ @Override public Set<String> keySet() { checkAndCopy(); return wrapped.keySet(); } /** * @see IValueMap#makeImmutable() */ @Override public IValueMap makeImmutable() { return wrapped.makeImmutable(); } /** * @see java.util.Map#put(Object, Object) */ @Override public Object put(final String key, final Object value) { checkAndCopy(); return wrapped.put(key, value); } /** * @see java.util.Map#putAll(Map) */ @Override public void putAll(final Map<? extends String, ?> map) { checkAndCopy(); wrapped.putAll(map); } /** * @see java.util.Map#remove(Object) */ @Override public Object remove(final Object key) { checkAndCopy(); return wrapped.remove(key); } /** * @see java.util.Map#size() */ @Override public int size() { return wrapped.size(); } /** * @see java.util.Map#values() */ @Override public Collection<Object> values() { return wrapped.values(); } // // // // getAs convenience methods // // /** * @see IValueMap#getAsBoolean(String) * */ @Override public Boolean getAsBoolean(final String key) { return wrapped.getAsBoolean(key); } /** * @see IValueMap#getAsBoolean(String, boolean) * */ @Override public boolean getAsBoolean(final String key, final boolean defaultValue) { return wrapped.getAsBoolean(key, defaultValue); } /** * @see IValueMap#getAsInteger(String) */ @Override public Integer getAsInteger(final String key) { return wrapped.getAsInteger(key); } /** * @see IValueMap#getAsInteger(String, int) */ @Override public int getAsInteger(final String key, final int defaultValue) { return wrapped.getAsInteger(key, defaultValue); } /** * @see IValueMap#getAsLong(String) */ @Override public Long getAsLong(final String key) { return wrapped.getAsLong(key); } /** * @see IValueMap#getAsLong(String, long) */ @Override public long getAsLong(final String key, final long defaultValue) { return wrapped.getAsLong(key, defaultValue); } /** * @see IValueMap#getAsDouble(String) */ @Override public Double getAsDouble(final String key) { return wrapped.getAsDouble(key); } /** * @see IValueMap#getAsDouble(String, double) */ @Override public double getAsDouble(final String key, final double defaultValue) { return wrapped.getAsDouble(key, defaultValue); } /** * @see IValueMap#getAsDuration(String) */ @Override public Duration getAsDuration(final String key) { return wrapped.getAsDuration(key); } /** * @see IValueMap#getAsDuration(String, Duration) */ @Override public Duration getAsDuration(final String key, final Duration defaultValue) { return wrapped.getAsDuration(key, defaultValue); } /** * @see IValueMap#getAsTime(String) */ @Override public Time getAsTime(final String key) { return wrapped.getAsTime(key); } /** * @see IValueMap#getAsTime(String, Time) */ @Override public Time getAsTime(final String key, final Time defaultValue) { return wrapped.getAsTime(key, defaultValue); } /** * @see IValueMap#getAsEnum(String, Class) */ @Override public <T extends Enum<T>> T getAsEnum(final String key, final Class<T> eClass) { return wrapped.getAsEnum(key, eClass); } /** * @see IValueMap#getAsEnum */ @Override public <T extends Enum<T>> T getAsEnum(final String key, final T defaultValue) { return wrapped.getAsEnum(key, defaultValue); } /** * @see IValueMap#getAsEnum(String, Class, Enum) */ @Override public <T extends Enum<T>> T getAsEnum(final String key, final Class<T> eClass, final T defaultValue) { return wrapped.getAsEnum(key, eClass, defaultValue); } }