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

org.apache.sling.api.wrappers.CompositeValueMap Maven / Gradle / Ivy

Go to download

The Apache Sling API defines an extension to the Servlet API 2.4 to provide access to content and unified access to request parameters hiding the differences between the different methods of transferring parameters from client to server. Note that the Apache Sling API bundle does not include the Servlet API but instead requires the API to be provided by the Servlet container in which the Apache Sling framework is running or by another bundle.

There is a newer version: 2.27.6
Show newest version
/*
 * 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.sling.api.wrappers;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.sling.api.resource.ValueMap;

/**
 * An implementation of the {@link ValueMap} based on two {@link ValueMap}s:
 * - One containing the properties
 * - Another one containing the defaults to use in case the properties map
 *   does not contain the values.
 * In case you would like to avoid duplicating properties on multiple resources,
 * you can use a CompositeValueMap to get a concatenated map of
 * properties.
 * @since 2.3 (Sling API Bundle 2.5.0)
 */
public class CompositeValueMap implements ValueMap {

    /**
     * Current properties
     */
    private final ValueMap properties;

    /**
     * Default properties
     */
    private final ValueMap defaults;

    /**
     * Merge mode
     */
    private final boolean merge;

    /**
     * Constructor
     * @param properties The {@link ValueMap} to read from
     * @param defaults The default {@link ValueMap} to use as fallback
     */
    public CompositeValueMap(final ValueMap properties, final ValueMap defaults) {
        this(properties, defaults, true);
    }

    /**
     * Constructor
     * @param properties The {@link ValueMap} to read from
     * @param defaults The default {@link ValueMap} to use as fallback
     * @param merge Merge flag
     *              - If true, getting a key would return the
     *              current property map's value (if available), even if the
     *              corresponding default does not exist.
     *              - If false, getting a key would return
     *              null if the corresponding default does not
     *              exist
     */
    public CompositeValueMap(final ValueMap properties, final ValueMap defaults, boolean merge) {
        if (properties == null) {
            throw new IllegalArgumentException("Properties need to be provided");
        }
        this.properties = properties;
        this.defaults = defaults != null ? defaults : ValueMap.EMPTY;
        this.merge = merge;
    }

    // ---- ValueMap

    /**
     * {@inheritDoc}
     */
    public  T get(final String key, final Class type) {
        if (merge || defaults.containsKey(key)) {
            // Check if property has been provided, if not use defaults
            if (properties.containsKey(key)) {
                return properties.get(key, type);
            } else {
                return defaults.get(key, type);
            }
        }

        // Override mode and no default value provided for this key
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public  T get(final String key, final T defaultValue) {
        if (defaultValue == null) {
            return (T) get(key);
        }

        T value = get(key, (Class) defaultValue.getClass());
        if (value != null) {
            return value;
        }

        return defaultValue;
    }


    // ---- Map

    /**
     * {@inheritDoc}
     */
    public int size() {
        return keySet().size();
    }

    /**
     * {@inheritDoc}
     */
    public boolean isEmpty() {
        if ( defaults.size() > 0 || (merge && properties.size() > 0) ) {
            return false;
        }
        return size() == 0;
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsKey(final Object key) {
        return keySet().contains(key.toString());
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsValue(final Object value) {
        return values().contains(value);
    }

    /**
     * {@inheritDoc}
     */
    public Object get(final Object key) {
        if (merge || defaults.containsKey(key)) {
            // Check if property has been provided, if not use defaults
            if (properties.containsKey(key)) {
                return properties.get(key);
            } else {
                return defaults.get(key);
            }
        }

        // Override mode and no default value provided for this key
        return null;
    }

    /**
     * {@inheritDoc}
     */
    public Object put(final String aKey, final Object value) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    public Object remove(final Object key) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    public void putAll(final Map properties) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    public void clear() {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     */
    public Set keySet() {
        return buildAggregatedMap().keySet();
    }

    /**
     * {@inheritDoc}
     */
    public Collection values() {
        return buildAggregatedMap().values();
    }

    /**
     * {@inheritDoc}
     */
    public Set> entrySet() {
        return buildAggregatedMap().entrySet();
    }

    /**
     * Build the aggregated map containing all values.
     */
    private Map buildAggregatedMap() {
        final Map entries = new HashMap();

        // Add properties in merge mode or if defaults exists
        for (final Entry entry : properties.entrySet()) {
            if (merge || defaults.containsKey(entry.getKey())) {
                entries.put(entry.getKey(), entry.getValue());
            }
        }

        // Add missing defaults
        for (final Entry entry : defaults.entrySet()) {
            if ( ! entries.containsKey(entry.getKey()) ) {
                entries.put(entry.getKey(), entry.getValue());
            }
        }

        return entries;
    }
}