|
Author: doogie
Date: Thu Jan 28 20:09:34 2010 New Revision: 904248 URL: http://svn.apache.org/viewvc?rev=904248&view=rev Log: Add a map stack implementation that is not hard-coded to only take string keys, and doesn't auto-add itself as 'context'. Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/MapContext.java Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/MapContext.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/MapContext.java?rev=904248&view=auto ============================================================================== --- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/MapContext.java (added) +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/MapContext.java Thu Jan 28 20:09:34 2010 @@ -0,0 +1,348 @@ +/******************************************************************************* + * 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.ofbiz.base.util.collections; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import javolution.lang.Reusable; +import javolution.context.ObjectFactory; +import javolution.util.FastList; +import javolution.util.FastMap; +import javolution.util.FastSet; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.UtilGenerics; + + +/** + * Map Stack + * + */ +public class MapContext<K, V> implements Map<K, V>, Reusable, LocalizedMap<V> { + + public static final String module = MapContext.class.getName(); + + protected static final ObjectFactory<MapContext<?, ?>> mapStackFactory = new ObjectFactory<MapContext<?, ?>>() { + @Override + protected MapContext<?, ?> create() { + return new MapContext<Object, Object>(); + } + }; + + public static final <K, V> MapContext<K, V> getMapContext() { + return (MapContext<K, V>) UtilGenerics.<K, V>checkMap(mapStackFactory.object()); + } + + public static <K, V> MapContext<K, V> createMapContext() { + MapContext<K, V> newValue = MapContext.getMapContext(); + // initialize with a single entry + newValue.push(); + return newValue; + } + + @SuppressWarnings("unchecked") + public static <K, V> MapContext<K, V> createMapContext(Map<K, V> baseMap) { + MapContext<K, V> newValue = MapContext.getMapContext(); + if (baseMap instanceof MapContext) { + newValue.stackList.addAll(((MapContext) baseMap).stackList); + } else { + newValue.stackList.add(0, baseMap); + } + return newValue; + } + + /** Does a shallow copy of the internal stack of the passed MapContext; enables simultaneous stacks that share common parent Maps */ + public static <K, V> MapContext<K, V> createMapContext(MapContext<K, V> source) { + MapContext<K, V> newValue = MapContext.getMapContext(); + newValue.stackList.addAll(source.stackList); + return newValue; + } + + protected MapContext() { + super(); + } + + protected List<Map<K, V>> stackList = FastList.newInstance(); + + public void reset() { + stackList = FastList.newInstance(); + } + + /** Puts a new Map on the top of the stack */ + public void push() { + Map<K, V> newMap = FastMap.newInstance(); + this.stackList.add(0,newMap); + } + + /** Puts an existing Map on the top of the stack (top meaning will override lower layers on the stack) */ + public void push(Map<K, V> existingMap) { + if (existingMap == null) { + throw new IllegalArgumentException("Error: cannot push null existing Map onto a MapContext"); + } + this.stackList.add(0, existingMap); + } + + /** Puts an existing Map on the BOTTOM of the stack (bottom meaning will be overriden by lower layers on the stack, ie everything else already there) */ + public void addToBottom(Map<K, V> existingMap) { + if (existingMap == null) { + throw new IllegalArgumentException("Error: cannot add null existing Map to bottom of a MapContext"); + } + this.stackList.add(existingMap); + } + + /** Remove and returns the Map from the top of the stack; if there is only one Map on the stack it returns null and does not remove it */ + public Map<K, V> pop() { + // always leave at least one Map in the List, ie never pop off the last Map + if (this.stackList.size() > 1) { + return stackList.remove(0); + } else { + return null; + } + } + + /** + * Creates a MapContext object that has the same Map objects on its stack; + * meant to be used to enable a + * situation where a parent and child context are operating simultaneously + * using two different MapContext objects, but sharing the Maps in common + */ + public MapContext<K, V> standAloneStack() { + MapContext<K, V> standAlone = MapContext.createMapContext(this); + return standAlone; + } + + /** + * Creates a MapContext object that has the same Map objects on its stack, + * but with a new Map pushed on the top; meant to be used to enable a + * situation where a parent and child context are operating simultaneously + * using two different MapContext objects, but sharing the Maps in common + */ + public MapContext<K, V> standAloneChildStack() { + MapContext<K, V> standAloneChild = MapContext.createMapContext(this); + standAloneChild.push(); + return standAloneChild; + } + + /* (non-Javadoc) + * @see java.util.Map#size() + */ + public int size() { + // a little bit tricky; to represent the apparent size we need to aggregate all keys and get a count of unique keys + // this is a bit of a slow way, but gets the best number possible + Set<K> keys = this.keySet(); + return keys.size(); + } + + /* (non-Javadoc) + * @see java.util.Map#isEmpty() + */ + public boolean isEmpty() { + // walk the stackList and if any is not empty, return false; otherwise return true + for (Map<K, V> curMap: this.stackList) { + if (!curMap.isEmpty()) { + return false; + } + } + return true; + } + + /* (non-Javadoc) + * @see java.util.Map#containsKey(java.lang.Object) + */ + public boolean containsKey(Object key) { + // walk the stackList and for the first place it is found return true; otherwise refurn false + for (Map<K, V> curMap: this.stackList) { + if (curMap.containsKey(key)) { + return true; + } + } + return false; + } + + /* (non-Javadoc) + * @see java.util.Map#containsValue(java.lang.Object) + */ + public boolean containsValue(Object value) { + // walk the stackList and the entries for each Map and if nothing is in for the current key, consider it an option, otherwise ignore + Set<K> resultKeySet = FastSet.newInstance(); + for (Map<K, V> curMap: this.stackList) { + for (Map.Entry<K, V> curEntry: curMap.entrySet()) { + if (!resultKeySet.contains(curEntry.getKey())) { + resultKeySet.add(curEntry.getKey()); + if (value == null) { + if (curEntry.getValue() == null) { + return true; + } + } else { + if (value.equals(curEntry.getValue())) { + return true; + } + } + } + } + } + return false; + } + + /* (non-Javadoc) + * @see java.util.Map#get(java.lang.Object) + */ + public V get(Object key) { + // walk the stackList and for the first place it is found return true; otherwise refurn false + for (Map<K, V> curMap: this.stackList) { + // only return if the curMap contains the key, rather than checking for null; this allows a null at a lower level to override a value at a higher level + if (curMap.containsKey(key)) { + return curMap.get(key); + } + } + return null; + } + + /* (non-Javadoc) + * @see org.ofbiz.base.util.collections.LocalizedMap#get(java.lang.String, java.util.Locale) + */ + public V get(String name, Locale locale) { + // walk the stackList and for the first place it is found return true; otherwise refurn false + for (Map<K, V> curMap: this.stackList) { + // only return if the curMap contains the key, rather than checking for null; this allows a null at a lower level to override a value at a higher level + if (curMap.containsKey(name)) { + if (curMap instanceof LocalizedMap) { + LocalizedMap<V> lmap = UtilGenerics.cast(curMap); + return lmap.get(name, locale); + } else { + return curMap.get(name); + } + } + } + return null; + } + + /* (non-Javadoc) + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + public V put(K key, V value) { + // all write operations are local: only put in the Map on the top of the stack + Map<K, V> currentMap = this.stackList.get(0); + return currentMap.put(key, value); + } + + /* (non-Javadoc) + * @see java.util.Map#remove(java.lang.Object) + */ + public V remove(Object key) { + // all write operations are local: only remove from the Map on the top of the stack + Map<K, V> currentMap = this.stackList.get(0); + return currentMap.remove(key); + } + + /* (non-Javadoc) + * @see java.util.Map#putAll(java.util.Map) + */ + public void putAll(Map<? extends K, ? extends V> arg0) { + // all write operations are local: only put in the Map on the top of the stack + Map<K, V> currentMap = this.stackList.get(0); + currentMap.putAll(arg0); + } + + /* (non-Javadoc) + * @see java.util.Map#clear() + */ + public void clear() { + // all write operations are local: only clear the Map on the top of the stack + this.stackList.get(0).clear(); + } + + /* (non-Javadoc) + * @see java.util.Map#keySet() + */ + public Set<K> keySet() { + // walk the stackList and aggregate all keys + Set<K> resultSet = FastSet.newInstance(); + for (Map<K, V> curMap: this.stackList) { + resultSet.addAll(curMap.keySet()); + } + return Collections.unmodifiableSet(resultSet); + } + + /* (non-Javadoc) + * @see java.util.Map#values() + */ + public Collection<V> values() { + // walk the stackList and the entries for each Map and if nothing is in for the current key, put it in + Set<K> resultKeySet = FastSet.newInstance(); + List<V> resultValues = FastList.newInstance(); + for (Map<K, V> curMap: this.stackList) { + for (Map.Entry<K, V> curEntry: curMap.entrySet()) { + if (!resultKeySet.contains(curEntry.getKey())) { + resultKeySet.add(curEntry.getKey()); + resultValues.add(curEntry.getValue()); + } + } + } + return Collections.unmodifiableCollection(resultValues); + } + + /* (non-Javadoc) + * @see java.util.Map#entrySet() + */ + public Set<Map.Entry<K, V>> entrySet() { + // walk the stackList and the entries for each Map and if nothing is in for the current key, put it in + Set<K> resultKeySet = FastSet.newInstance(); + Set<Map.Entry<K, V>> resultEntrySet = FastSet.newInstance(); + for (Map<K, V> curMap: this.stackList) { + for (Map.Entry<K, V> curEntry: curMap.entrySet()) { + if (!resultKeySet.contains(curEntry.getKey())) { + resultKeySet.add(curEntry.getKey()); + resultEntrySet.add(curEntry); + } + } + } + return Collections.unmodifiableSet(resultEntrySet); + } + + @Override + public String toString() { + StringBuilder fullMapString = new StringBuilder(); + int curLevel = 0; + for (Map<K, V> curMap: this.stackList) { + fullMapString.append("============================== Start stack level " + curLevel + "\n"); + for (Map.Entry<K, V> curEntry: curMap.entrySet()) { + + fullMapString.append("==>["); + fullMapString.append(curEntry.getKey()); + fullMapString.append("]:"); + // skip the instances of MapContext to avoid infinite loop + if (curEntry.getValue() instanceof MapContext) { + fullMapString.append("<Instance of MapContext, not printing to avoid infinite recursion>"); + } else { + fullMapString.append(curEntry.getValue()); + } + fullMapString.append("\n"); + } + fullMapString.append("============================== End stack level " + curLevel + "\n"); + curLevel++; + } + return fullMapString.toString(); + } +} |
| Free forum by Nabble | Edit this page |
