![JAR search and dependency download from the Maven repository](/logo.png)
com.day.cq.wcm.foundation.forms.MergedValueMap Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* Copyright 1997-2009 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.wcm.foundation.forms;
import java.lang.reflect.Array;
import java.util.*;
import org.apache.commons.lang.ObjectUtils;
import org.apache.jackrabbit.util.ISO8601;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
/**
* {@linkplain MergedValueMap} merges the values of the value maps from multiple
* resources. It merges the values of all value maps behind the resources, ie.
* provides a null value for a key if the value is not the same in all resources
* and only presents a value if that one is present in exactly all of the
* resources.
*
*
* It is optimized for the forms module, ie. on calls to
* {@link #get(String, Class)} with String[]
as type (see
* {@link FormsHelper#getValues(org.apache.sling.api.SlingHttpServletRequest, Resource)}
* ).
*
*
* Note: this class is not synchronized, ie. not thread-safe.
*
*/
public class MergedValueMap implements ValueMap {
private List resources;
private Map cache;
public MergedValueMap(List resources) {
this.resources = resources;
}
protected void readFully() {
if (cache == null) {
cache = fetchAndMergeAllValues();
}
}
protected Map fetchAndMergeAllValues() {
Map mergedMap = new HashMap();
boolean firstResource = true;
for (Resource resource : resources) {
ValueMap map = resource.adaptTo(ValueMap.class);
if (map != null) {
for (Entry entry : map.entrySet()) {
String key = entry.getKey();
if (mergedMap.containsKey(key)) {
// key was in a previous resource already
Object value = mergedMap.get(key);
if (value == null) {
// values were already different before, keep null
} else {
Object newValue = entry.getValue();
if (newValue != null && value.equals(newValue)) {
// same value as before, keep it in the cache
} else {
// different values found, store null
mergedMap.put(key, null);
}
}
} else {
// first access to this key
if (firstResource) {
// first resource, store current value
mergedMap.put(key, entry.getValue());
} else {
// new key, wasn't present in previous resources
mergedMap.put(key, null);
}
}
}
}
firstResource = false;
}
return mergedMap;
}
public Object get(Object key) {
readFully();
Object value = cache.get(key);
if (value == null) {
value = read((String) key);
}
return value;
}
private Object read(String key) {
Object value = null;
boolean firstResource = true;
boolean isArray = false;
for (Resource resource : resources) {
ValueMap map = resource.adaptTo(ValueMap.class);
if (map != null) {
if (firstResource) {
value = map.get(key);
if (value == null) break;
isArray = value.getClass().isArray();
} else {
Object newValue = map.get(key);
if (newValue == null) {
value = null;
break;
}
boolean newIsArray = newValue.getClass().isArray();
if (isArray != newIsArray ||
(isArray && !Arrays.equals((Object[]) value, (Object[]) newValue)) ||
(!isArray && !ObjectUtils.equals(value, newValue))) {
// break if:
// - one of the values is single and the other mutiple
// - or both are mutliple but the values do not match
// - or both are single but do not match
value = null;
break;
}
}
}
firstResource = false;
}
cache.put(key, value);
return value;
}
@SuppressWarnings("unchecked")
public T get(String name, Class type) {
readFully();
if (type == null) {
return (T) get(name);
}
return convert(get(name), type);
}
@SuppressWarnings("unchecked")
public T get(String name, T defaultValue) {
readFully();
T value = get(name, (Class) defaultValue.getClass());
return value == null ? defaultValue : value;
}
public int size() {
readFully();
return cache.size();
}
public boolean isEmpty() {
return size() == 0;
}
public boolean containsKey(Object key) {
readFully();
return cache.containsKey(key);
}
public boolean containsValue(Object value) {
readFully();
return cache.containsValue(value);
}
public Set> entrySet() {
readFully();
return cache.entrySet();
}
public Set keySet() {
readFully();
return cache.keySet();
}
public Collection