001/**
002 * Copyright 2005-2015 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.rice.krad.uif.util;
017
018import java.io.Serializable;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.HashMap;
022import java.util.Map;
023import java.util.Set;
024
025import org.kuali.rice.krad.datadictionary.Copyable;
026
027/**
028 * Map implementation for internal use by a lifecycle element.
029 *
030 * <p>Mutability of the map will follow the semantics for the lifecycle element.</p>
031 *
032 * @author Kuali Rice Team (rice.collab@kuali.org)
033 * @param <K> map key type
034 * @param <V> map value type
035 */
036public class LifecycleAwareMap<K, V> implements Map<K, V>, Copyable, Serializable {
037    private static final long serialVersionUID = -2872079344892779899L;
038
039    /**
040     * The lifecycle element this map is related to.
041     */
042    private final LifecycleElement lifecycleElement;
043
044    /**
045     * Delegating map implementation.
046     */
047    private Map<K, V> delegate;
048
049    /**
050     * Create a new map instance for use with a lifecycle element.
051     *
052     * @param lifecycleElement The lifecycle element to use for mutability checks.
053     */
054    public LifecycleAwareMap(LifecycleElement lifecycleElement) {
055        this.lifecycleElement = lifecycleElement;
056        this.delegate = Collections.emptyMap();
057    }
058
059    /**
060     * Create a new list instance, based on another list.
061     *
062     * @param lifecycleElement The lifecycle element to use for mutability checks.
063     * @param delegate The list to wrap.
064     */
065    public LifecycleAwareMap(LifecycleElement lifecycleElement, Map<K, V> delegate) {
066        this.lifecycleElement = lifecycleElement;
067        this.delegate = delegate;
068    }
069
070    /**
071     * Ensure that the delegate list can be modified.
072     */
073    private void ensureMutable() {
074        lifecycleElement.checkMutable(true);
075
076        if (delegate == Collections.EMPTY_MAP) {
077            delegate = new HashMap<K, V>();
078        }
079    }
080
081    @Override
082    public int size() {
083        return this.delegate.size();
084    }
085
086    @Override
087    public boolean isEmpty() {
088        return this.delegate.isEmpty();
089    }
090
091    @Override
092    public boolean containsKey(Object key) {
093        return this.delegate.containsKey(key);
094    }
095
096    @Override
097    public boolean containsValue(Object value) {
098        return this.delegate.containsValue(value);
099    }
100
101    @Override
102    public V get(Object key) {
103        return this.delegate.get(key);
104    }
105
106    @Override
107    public V put(K key, V value) {
108        ensureMutable();
109        return this.delegate.put(key, value);
110    }
111
112    @Override
113    public V remove(Object key) {
114        lifecycleElement.checkMutable(true);
115        return delegate == Collections.EMPTY_MAP ? null : this.delegate.remove(key);
116    }
117
118    @Override
119    public void putAll(Map<? extends K, ? extends V> m) {
120        ensureMutable();
121        this.delegate.putAll(m);
122    }
123
124    @Override
125    public void clear() {
126        if (delegate != Collections.EMPTY_MAP) {
127            this.delegate.clear();
128        }
129    }
130
131    @Override
132    public Set<K> keySet() {
133        return this.delegate.keySet();
134    }
135
136    @Override
137    public Collection<V> values() {
138        return this.delegate.values();
139    }
140
141    @Override
142    public Set<java.util.Map.Entry<K, V>> entrySet() {
143        // TODO: Return entrySet wrapper
144        return this.delegate.entrySet();
145    }
146
147    @Override
148    public boolean equals(Object o) {
149        return this.delegate.equals(o);
150    }
151
152    @Override
153    public int hashCode() {
154        return this.delegate.hashCode();
155    }
156
157    /**
158     * @see java.lang.Object#clone()
159     */
160    @Override
161    public Object clone() throws CloneNotSupportedException {
162        return super.clone();
163    }
164
165}