ParameterMap.java
/*
* 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.catalina.util;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.tomcat.util.res.StringManager;
/**
* Implementation of <strong>java.util.Map</strong> that includes a <code>locked</code> property. This class can be used
* to safely expose Catalina internal parameter map objects to user classes without having to clone them in order to
* avoid modifications. When first created, a <code>ParameterMap</code> instance is not locked.
*
* @param <K> The type of Key
* @param <V> The type of Value
*
* @author Craig R. McClanahan
*/
public final class ParameterMap<K, V> implements Map<K,V>, Serializable {
private static final long serialVersionUID = 2L;
private final Map<K,V> delegatedMap;
private final Map<K,V> unmodifiableDelegatedMap;
/**
* Construct a new, empty map with the default initial capacity and load factor.
*/
public ParameterMap() {
delegatedMap = new LinkedHashMap<>();
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* Construct a new, empty map with the specified initial capacity and default load factor.
*
* @param initialCapacity The initial capacity of this map
*/
public ParameterMap(int initialCapacity) {
delegatedMap = new LinkedHashMap<>(initialCapacity);
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* Construct a new, empty map with the specified initial capacity and load factor.
*
* @param initialCapacity The initial capacity of this map
* @param loadFactor The load factor of this map
*/
public ParameterMap(int initialCapacity, float loadFactor) {
delegatedMap = new LinkedHashMap<>(initialCapacity, loadFactor);
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* Construct a new map with the same mappings as the given map.
*
* @param map Map whose contents are duplicated in the new map
*/
public ParameterMap(Map<K,V> map) {
delegatedMap = new LinkedHashMap<>(map);
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* Optimised constructor for ParameterMap.
*
* @see "https://bz.apache.org/bugzilla/show_bug.cgi?id=69285"
*
* @param map Map whose contents are duplicated in the new map
*/
public ParameterMap(ParameterMap<K,V> map) {
delegatedMap = new LinkedHashMap<>(map.delegatedMap);
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* The current lock state of this parameter map.
*/
private boolean locked = false;
/**
* @return the locked state of this parameter map.
*/
public boolean isLocked() {
return locked;
}
/**
* Set the locked state of this parameter map.
*
* @param locked The new locked state
*/
public void setLocked(boolean locked) {
this.locked = locked;
}
/**
* The string manager for this package.
*/
private static final StringManager sm = StringManager.getManager("org.apache.catalina.util");
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public void clear() {
checkLocked();
delegatedMap.clear();
}
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public V put(K key, V value) {
checkLocked();
return delegatedMap.put(key, value);
}
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public void putAll(Map<? extends K,? extends V> map) {
checkLocked();
delegatedMap.putAll(map);
}
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public V remove(Object key) {
checkLocked();
return delegatedMap.remove(key);
}
private void checkLocked() {
if (locked) {
throw new IllegalStateException(sm.getString("parameterMap.locked"));
}
}
@Override
public int size() {
return delegatedMap.size();
}
@Override
public boolean isEmpty() {
return delegatedMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return delegatedMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return delegatedMap.containsValue(value);
}
@Override
public V get(Object key) {
return delegatedMap.get(key);
}
/**
* {@inheritDoc}
* <p>
* Returns an <strong>unmodifiable</strong> {@link Set} view of the keys contained in this map if it is locked.
*/
@Override
public Set<K> keySet() {
if (locked) {
return unmodifiableDelegatedMap.keySet();
}
return delegatedMap.keySet();
}
/**
* {@inheritDoc}
* <p>
* Returns an <strong>unmodifiable</strong> {@link Collection} view of the values contained in this map if it is
* locked.
*/
@Override
public Collection<V> values() {
if (locked) {
return unmodifiableDelegatedMap.values();
}
return delegatedMap.values();
}
/**
* {@inheritDoc}
* <p>
* Returns an <strong>unmodifiable</strong> {@link Set} view of the mappings contained in this map if it is locked.
*/
@Override
public Set<Map.Entry<K,V>> entrySet() {
if (locked) {
return unmodifiableDelegatedMap.entrySet();
}
return delegatedMap.entrySet();
}
}