All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tapestry5.util.DefaultPrimaryKeyEncoder Maven / Gradle / Ivy

Go to download

Central module for Tapestry, containing interfaces to the Java Servlet API and all core services and components.

There is a newer version: 5.8.6
Show newest version
// Copyright 2007, 2009, 2010 The Apache Software Foundation
//
// 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 org.apache.tapestry5.util;

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.tapestry5.PrimaryKeyEncoder;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;

/**
 * A default, extensible version of {@link org.apache.tapestry5.PrimaryKeyEncoder} that is based on loading known values
 * into an internal map. When there's a reasonable number (hundreds, perhaps thousands) of items to choose from, and
 * those items are fast and cheap to read and instantiate, this implementation is a good bet. For very large result
 * sets, you'll need to create your own implementation of {@link PrimaryKeyEncoder}.
 *
 * @param  the key type (which must be serializable)
 * @param  the value type
 * @deprecated See deprecation notes for {@link org.apache.tapestry5.PrimaryKeyEncoder}.
 */
public class DefaultPrimaryKeyEncoder implements PrimaryKeyEncoder
{
    private final Map keyToValue = new LinkedHashMap();

    private final Map valueToKey = CollectionFactory.newMap();

    private Set deletedKeys;

    private K currentKey;

    private final Class keyType;

    /**
     * Compatibility with 5.0: new encoder, key type unknown. You will want to use the other constructor and
     * specify the key type.
     */
    public DefaultPrimaryKeyEncoder()
    {
        this(null);
    }

    /**
     * @since 5.1.0.0
     */
    public DefaultPrimaryKeyEncoder(Class keyType)
    {
        this.keyType = keyType;
    }


    public Class getKeyType()
    {
        return keyType;
    }

    /**
     * Adds a new key/value pair to the encoder.
     */
    public final void add(K key, V value)
    {
        assert key != null;
        assert value != null;
        V existing = keyToValue.get(key);
        if (existing != null) throw new IllegalArgumentException(PublicUtilMessages.duplicateKey(key, value, existing));

        keyToValue.put(key, value);

        // TODO: Ensure that the value is unique?

        valueToKey.put(value, key);
    }

    /**
     * Returns the values previously {@link #add(Serializable, Object) added to the encoder}, in the order in which
     * they were added. Values that are deleted are not returned.
     *
     * @return ordered list of values
     */
    public final List getValues()
    {
        return valuesNotInKeySet(deletedKeys);
    }

    /**
     * Returns a list of all the values except those values whose keys are in the provided set. The set may be
     * null, in which case all values are returned.
     *
     * @param keySet set of keys identifying values to exclude, or null to exclude no values
     * @return values (not in the set) in order origionally added
     */
    protected final List valuesNotInKeySet(Set keySet)
    {
        if (keySet == null || keySet.isEmpty()) return getAllValues();

        List result = CollectionFactory.newList();

        for (Map.Entry entry : keyToValue.entrySet())
        {

            if (keySet.contains(entry.getKey())) continue;

            result.add(entry.getValue());
        }

        return result;
    }

    public final List getAllValues()
    {
        List result = CollectionFactory.newList();

        for (Map.Entry entry : keyToValue.entrySet())
        {
            result.add(entry.getValue());
        }

        return result;
    }

    /**
     * For a previously {@link #add(Serializable, Object) added key/value pair}, returns the key corresponding to the
     * given value.
     */
    public final K toKey(V value)
    {
        assert value != null;
        currentKey = valueToKey.get(value);

        if (currentKey == null) throw new IllegalArgumentException(PublicUtilMessages.missingValue(value, valueToKey
                .keySet()));

        return currentKey;
    }

    public final V toValue(K key)
    {
        V result = keyToValue.get(key);

        if (result == null)
        {
            result = provideMissingObject(key);

            currentKey = key;
        }
        else
        {
            currentKey = key;
        }

        return result;
    }

    /**
     * Invoked by {@link #toValue(Serializable)} whenever a key can not be converted to a value using the internal
     * cache. This is an opportunity to record the fact that an error occured (they key was not valuable, possibly
     * because it points to a deleted entity object) and provide a temporary object. This method may return null, but in
     * a typical application, that will likely case NullPointerExceptions further down the processing chain.
     * 

* This implementation returns null, and is intended to be overriden in subclasses. * * @param key key for which a value is required * @return a substitute value, or null */ protected V provideMissingObject(K key) { return null; } public final boolean isDeleted() { return inKeySet(deletedKeys); } public final void setDeleted(boolean value) { deletedKeys = modifyKeySet(deletedKeys, value); } /** * Returns true if the current key is in the provided set. * * @param keySet the set of keys to check, or null * @return true if the key is in the set, false if it is missing (or if keySet is null) */ protected final boolean inKeySet(Set keySet) { return keySet != null && keySet.contains(currentKey); } /** * Modifies a keySet to add or remove the current key. If necessary, a new Set is created. *

* Useage: private Set myFlagKeys; *

* public boolean void setMyFlag(boolean value) { myFlagKeys = modifySet(myFlagKeys, value); } * * @param keySet the set of keys, or null * @param value true to add the current key, false to remove * @return the provided key set, or a new one */ protected final Set modifyKeySet(Set keySet, boolean value) { if (keySet == null) { if (!value) return null; keySet = CollectionFactory.newSet(); } if (value) keySet.add(currentKey); else keySet.remove(currentKey); return keySet; } /** * Does nothing. Subclasses may override as necessary. */ public void prepareForKeys(List keys) { } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy