/* * Copyright 2013 Cameron Beccario * * Licensed 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 net.nullschool.grains; import net.nullschool.collect.ConstMap; import java.util.Collection; import java.util.Map; /** * 2013-03-24<p/> * * A Grain is an {@link ConstMap immutable map} of String to Object that contains permanent keys, i.e., keys that * cannot be disassociated from the map. Grains permit {@code null} values but disallow {@code null} keys.<p/> * * The set of permanent keys, called the "basis", differs depending on the grain implementation, and each basis key * may restrict the type of values it can be associated with. This is roughly analogous to how instances of a class * share the same set of fields, and each field stores values only of a particular type. Attempts to disassociate a * basis key or associate it with {@code null} results in the key becoming associated with its <i>default value</i>. * Generally, a key's default value is {@code null} if its type restriction is a reference type, otherwise {@code 0} * for primitive types. However, some grain implementations may (optionally) specify a non-null/non-zero default * value for a key.<p/> * * A grain can associate and disassociate non-basis keys, just like a normal map. To differentiate them from the * basis, these keys are called "extensions". Extension keys may also (optionally) restrict their associated * values.<p/> * * The {@link #keySet}, {@link #values}, {@link #entrySet}, and {@link #iterator} methods present the <i>union</i> * of the basis and extensions. There is no guaranteed iteration order. When desired, the {@link #extensions} method * provides a view of just the extension associations.<p/> * * Entries may be "modified" using the {@link #with} and {@link #without} methods inherited from {@link ConstMap}. * These methods return a new instance, leaving the original instance unmodified. As it can be expensive to construct * grain instances from a large sequence of {@code with} method invocations, the builder pattern is provided to * simplify construction. A mutable {@link GrainBuilder} instance containing the grain's current associations can be * retrieved using the {@link #newBuilder} method. After the builder is modified as desired, the {@link * GrainBuilder#build} method can be invoked to construct a new grain instance.<p/> * * @author Cameron Beccario */ public interface Grain extends ConstMap<String, Object> { /** * Returns a grain containing the entries of this grain plus the specified key-value association. No visible * change to this grain occurs.<p/> * * This method may throw ClassCastException if the value does not meet the typing requirements of the key, or * IllegalArgumentException if some property of the value is not suitable for the key. This method interprets * a {@code null} value to represent the <i>default value</i> of the key. Generally, a key's default value is * {@code null} if its type restriction is a reference type, otherwise {@code 0} for primitive types. However, * some keys may have a non-null/non-zero default value. For example, if a key's default value is <i>42</i>, * then invoking this method with a {@code null} value will associate that key with <i>42</i>.<p/> * * If the specified key is not a basis key, then the key-value association becomes an extension on this grain. * * @param key the key to associate. * @param value the value to be associated with the key. * @return a grain containing this grain's associations conjoined with the specified association. * @throws NullPointerException if the key is null. * @throws ClassCastException if the value is of a type not suitable for this grain. * @throws IllegalArgumentException if some property of the value is not suitable for this grain. */ @Override Grain with(String key, Object value); /** * Returns a grain containing the entries of this grain plus all the entries of the specified map. No visible * change to this grain occurs.<p/> * * The effect of this call is equivalent to invoking {@link #with} for each entry in the specified map. * * @param map mappings to conjoin with the associations in this grain. * @return a grain containing this grain's associations conjoined with the associations in the provided map. * @throws NullPointerException if the map is null, or any key is null. * @throws ClassCastException if any value is of a type not suitable for this grain. * @throws IllegalArgumentException if some property of any value in the map is not suitable for this grain. */ @Override Grain withAll(Map<? extends String, ?> map); /** * Returns a grain containing the associations of this grain minus the mapping for the specified key. No visible * change to this grain occurs.<p/> * * NOTE: This method violates the ConstMap contract if invoked with a basis key. Rather than remove the key, this * method associates it with its <i>default value</i>. * * @param key the key to de-associate. * @return a grain containing this grain's associations disjoined from the specified association. * @throws NullPointerException if the key is null. * @throws ClassCastException if the key is not a String. */ @Override Grain without(Object key); /** * Returns a grain containing the associations of this grain minus all the mappings for the specified keys. No * visible change to this grain occurs.<p/> * * The effect of this call is equivalent to invoking {@link #without} for each key in the specified collection.<p/> * * NOTE: This method violates the ConstMap contract if any key in the specified collection is a basis key. Rather * than remove the key, this method associates it with its <i>default value</i>. * * @param keys the keys to de-associate from this grain. * @return a grain containing this grain's associations disjoined from the keys in the provided collection. * @throws NullPointerException if the specified collection is null, or any key in the collection is null. * @throws ClassCastException if any key in the specified collection is not a String. */ @Override Grain withoutAll(Collection<?> keys); /** * Returns a new builder initialized with the same entries as this grain. * * @return a new builder instance copied from this grain. */ GrainBuilder newBuilder(); /** * Returns a ConstMap of this grain's extensions, if any. An extension is an extra entry on this grain instance * whose key is not a basis key, i.e., is not a permanent member of this grain. * * @return a map of all extensions on this grain, or an empty map if there are none. Never returns {@code null}. */ ConstMap<String, Object> extensions(); /** * {@inheritDoc} */ boolean equals(Object obj); /** * {@inheritDoc} */ int hashCode(); }