blob: 6abf0ce0ff7e45093f917a4ea66f06de19753cd1 [file] [log] [blame]
/*******************************************************************************
* 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.ofbiz.base.util.collections;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import org.apache.ofbiz.base.util.UtilProperties;
import org.apache.ofbiz.base.util.string.FlexibleStringExpander;
/**
* Generic ResourceBundle Map Wrapper, given ResourceBundle allows it to be used as a Map
*
*/
@SuppressWarnings("serial")
public class ResourceBundleMapWrapper implements Map<String, Object>, Serializable {
protected MapStack<String> rbmwStack;
protected ResourceBundle initialResourceBundle;
protected Map<String, Object> context;
protected ResourceBundleMapWrapper() {
rbmwStack = MapStack.create();
}
/**
* When creating new from a InternalRbmWrapper the one passed to the constructor should be the most specific or local InternalRbmWrapper, with more common ones pushed onto the stack progressively.
*/
public ResourceBundleMapWrapper(InternalRbmWrapper initialInternalRbmWrapper) {
this.initialResourceBundle = initialInternalRbmWrapper.getResourceBundle();
this.rbmwStack = MapStack.create(initialInternalRbmWrapper);
}
/** When creating new from a ResourceBundle the one passed to the constructor should be the most specific or local ResourceBundle, with more common ones pushed onto the stack progressively.
*/
public ResourceBundleMapWrapper(ResourceBundle initialResourceBundle) {
if (initialResourceBundle == null) {
throw new IllegalArgumentException("Cannot create ResourceBundleMapWrapper with a null initial ResourceBundle.");
}
this.initialResourceBundle = initialResourceBundle;
this.rbmwStack = MapStack.create(new InternalRbmWrapper(initialResourceBundle));
}
/** When creating new from a ResourceBundle the one passed to the constructor should be the most specific or local ResourceBundle, with more common ones pushed onto the stack progressively.
*/
public ResourceBundleMapWrapper(ResourceBundle initialResourceBundle, Map<String, Object> context) {
if (initialResourceBundle == null) {
throw new IllegalArgumentException("Cannot create ResourceBundleMapWrapper with a null initial ResourceBundle.");
}
this.initialResourceBundle = initialResourceBundle;
this.rbmwStack = MapStack.create(new InternalRbmWrapper(initialResourceBundle));
this.context = context;
}
/** Puts ResourceBundle on the BOTTOM of the stack (bottom meaning will be overriden by higher layers on the stack, ie everything else already there) */
public void addBottomResourceBundle(ResourceBundle topResourceBundle) {
this.rbmwStack.addToBottom(new InternalRbmWrapper(topResourceBundle));
}
/** Puts InternalRbmWrapper on the BOTTOM of the stack (bottom meaning will be overriden by higher layers on the stack, ie everything else already there) */
public void addBottomResourceBundle(InternalRbmWrapper topInternalRbmWrapper) {
this.rbmwStack.addToBottom(topInternalRbmWrapper);
}
/** Don't pass the locale to make sure it has the same locale as the base */
public void addBottomResourceBundle(String resource) {
if (this.initialResourceBundle == null) {
throw new IllegalArgumentException("Cannot add bottom resource bundle, this wrapper was not properly initialized (there is no base/initial ResourceBundle).");
}
this.addBottomResourceBundle(new InternalRbmWrapper(UtilProperties.getResourceBundle(resource, this.initialResourceBundle.getLocale())));
}
/** In general we don't want to use this, better to start with the more specific ResourceBundle and add layers of common ones...
* Puts ResourceBundle on the top of the stack (top meaning will override lower layers on the stack)
*/
public void pushResourceBundle(ResourceBundle topResourceBundle) {
this.rbmwStack.push(new InternalRbmWrapper(topResourceBundle));
}
public ResourceBundle getInitialResourceBundle() {
return this.initialResourceBundle;
}
public void clear() {
this.rbmwStack.clear();
}
public boolean containsKey(Object arg0) {
return this.rbmwStack.containsKey(arg0);
}
public boolean containsValue(Object arg0) {
return this.rbmwStack.containsValue(arg0);
}
public Set<Map.Entry<String, Object>> entrySet() {
return this.rbmwStack.entrySet();
}
public Object get(Object arg0) {
Object value = this.rbmwStack.get(arg0);
if (value == null) {
value = arg0;
} else if (context != null) {
try {
String str = (String) value;
return FlexibleStringExpander.expandString(str, context);
} catch (Exception e) {
// Potential ClassCastException - do nothing
}
}
return value;
}
public boolean isEmpty() {
return this.rbmwStack.isEmpty();
}
public Set<String> keySet() {
return this.rbmwStack.keySet();
}
public Object put(String key, Object value) {
return this.rbmwStack.put(key, value);
}
public void putAll(Map<? extends String, ? extends Object> arg0) {
this.rbmwStack.putAll(arg0);
}
public Object remove(Object arg0) {
return this.rbmwStack.remove(arg0);
}
public int size() {
return this.rbmwStack.size();
}
public Collection<Object> values() {
return this.rbmwStack.values();
}
public static class InternalRbmWrapper implements Map<String, Object>, Serializable {
protected ResourceBundle resourceBundle;
protected Map<String, Object> topLevelMap;
private boolean isMapInitialized = false;
public InternalRbmWrapper(ResourceBundle resourceBundle) {
if (resourceBundle == null) {
throw new IllegalArgumentException("Cannot create InternalRbmWrapper with a null ResourceBundle.");
}
this.resourceBundle = resourceBundle;
}
/**
* Creates the topLevelMap only when it is required
*/
private void createMapWhenNeeded() {
if (isMapInitialized) {
return;
}
// NOTE: this does NOT return all keys, ie keys from parent
// ResourceBundles, so we keep the resourceBundle object to look at
// when the main Map doesn't have a certain value
if (resourceBundle != null) {
Set<String> set = resourceBundle.keySet();
topLevelMap = new HashMap<String, Object>(set.size());
for (String key : set) {
Object value = resourceBundle.getObject(key);
topLevelMap.put(key, value);
}
} else {
topLevelMap = new HashMap<String, Object>(1);
}
topLevelMap.put("_RESOURCE_BUNDLE_", resourceBundle);
isMapInitialized = true;
}
/* (non-Javadoc)
* @see java.util.Map#size()
*/
public int size() {
if(isMapInitialized) {
// this is an approximate size, won't include elements from parent bundles
return topLevelMap.size() -1;
} else {
return resourceBundle.keySet().size();
}
}
/* (non-Javadoc)
* @see java.util.Map#isEmpty()
*/
public boolean isEmpty() {
if (isMapInitialized) {
return topLevelMap.isEmpty();
} else {
return resourceBundle.keySet().size() == 0;
}
}
/* (non-Javadoc)
* @see java.util.Map#containsKey(java.lang.Object)
*/
public boolean containsKey(Object arg0) {
if (isMapInitialized) {
if (topLevelMap.containsKey(arg0)) {
return true;
}
} else {
try {
if (this.resourceBundle.getObject((String) arg0) != null) {
return true;
}
} catch (NullPointerException e) {
// happens when arg0 is null
} catch (MissingResourceException e) {
// nope, not found... nothing, will automatically return
// false below
}
}
return false;
}
/* (non-Javadoc)
* @see java.util.Map#containsValue(java.lang.Object)
*/
public boolean containsValue(Object arg0) {
throw new RuntimeException("Not implemented for ResourceBundleMapWrapper");
}
/* (non-Javadoc)
* @see java.util.Map#get(java.lang.Object)
*/
public Object get(Object arg0) {
Object value = null;
if(isMapInitialized) {
value = this.topLevelMap.get(arg0);
}
if (resourceBundle != null) {
if (value == null) {
try {
value = this.resourceBundle.getObject((String) arg0);
} catch (MissingResourceException mre) {
// do nothing, this will be handled by recognition that the value is still null
}
}
}
return value;
}
/* (non-Javadoc)
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
public Object put(String arg0, Object arg1) {
throw new RuntimeException("Not implemented/allowed for ResourceBundleMapWrapper");
}
/* (non-Javadoc)
* @see java.util.Map#remove(java.lang.Object)
*/
public Object remove(Object arg0) {
throw new RuntimeException("Not implemented for ResourceBundleMapWrapper");
}
/* (non-Javadoc)
* @see java.util.Map#putAll(java.util.Map)
*/
public void putAll(Map<? extends String, ? extends Object> arg0) {
throw new RuntimeException("Not implemented for ResourceBundleMapWrapper");
}
/* (non-Javadoc)
* @see java.util.Map#clear()
*/
public void clear() {
throw new RuntimeException("Not implemented for ResourceBundleMapWrapper");
}
/* (non-Javadoc)
* @see java.util.Map#keySet()
*/
public Set<String> keySet() {
createMapWhenNeeded();
return this.topLevelMap.keySet();
}
/* (non-Javadoc)
* @see java.util.Map#values()
*/
public Collection<Object> values() {
createMapWhenNeeded();
return this.topLevelMap.values();
}
/* (non-Javadoc)
* @see java.util.Map#entrySet()
*/
public Set<Map.Entry<String, Object>> entrySet() {
createMapWhenNeeded();
return this.topLevelMap.entrySet();
}
public ResourceBundle getResourceBundle() {
return this.resourceBundle;
}
}
}