/* * 2012-3 Red Hat Inc. and/or its affiliates and other contributors. * * 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.overlord.rtgov.active.collection; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.overlord.rtgov.active.collection.predicate.Predicate; /** * This interface represents an active map. * */ public class ActiveMap extends ActiveCollection implements java.lang.Iterable<Object>, java.util.Map<Object,Object> { private static final int INITIAL_CAPACITY = 1000; private static final Logger LOG=Logger.getLogger(ActiveMap.class.getName()); private java.util.Map<Object,Object> _map=new java.util.HashMap<Object,Object>(INITIAL_CAPACITY); private java.util.Map<Object,Long> _mapTimestamps=new java.util.HashMap<Object,Long>(INITIAL_CAPACITY); private java.util.List<Object> _readCopy=null; /** * This constructor initializes the active map. * * @param name The name */ public ActiveMap(String name) { super(name); } /** * This constructor initializes the active collection. * * @param acs The Active Collection source */ public ActiveMap(ActiveCollectionSource acs) { super(acs); } /** * This constructor initializes the active map. * * @param acs The Active Collection source * @param map The map */ public ActiveMap(ActiveCollectionSource acs, java.util.Map<Object,Object> map) { super(acs); _map = map; } /** * This constructor initializes the active list. * * @param name The name * @param capacity The initial capacity of the list */ protected ActiveMap(String name, int capacity) { super(name); _map = new java.util.HashMap<Object,Object>(capacity); _mapTimestamps = new java.util.HashMap<Object,Long>(capacity); } /** * This constructor initializes the active map as a derived * version of the supplied collection, that applies the supplied predicate. * * @param name The name * @param parent The parent collection * @param context The context * @param predicate The predicate * @param properties The optional properties */ protected ActiveMap(String name, ActiveCollection parent, ActiveCollectionContext context, Predicate predicate, java.util.Map<String,Object> properties) { super(name, parent, context, predicate, properties); // Filter the parent map items, to determine which pass the predicate for (Object obj : (ActiveMap)parent) { Entry entry=(Entry)obj; if (predicate.evaluate(context, entry.getValue())) { doInsert(entry.getKey(), entry.getValue()); } } } /** * This method derives the content. * * @return The derived content */ protected java.util.Map<Object,Object> deriveContent() { java.util.Map<Object,Object> ret=new java.util.HashMap<Object,Object>(); ActiveCollection parent=getParent(); Predicate pred=getPredicate(); ActiveCollectionContext context=getContext(); if (parent != null && pred != null) { for (Object obj : (ActiveMap)parent) { Entry entry=(Entry)obj; if (pred.evaluate(context, entry.getValue())) { ret.put(entry.getKey(), entry.getValue()); } } } return (ret); } /** * This method returns the map. * * @return The map */ protected java.util.Map<Object,Object> getMap() { return (_map); } /** * {@inheritDoc} */ public int getSize() { if (!isDerived() || isActive()) { synchronized (_map) { return (_map.size()); } } else { java.util.Map<Object,Object> derived=deriveContent(); return (derived.size()); } } /** * This method returns the value associated with the supplied * key. * * @param key The key * @return The value, or null if none associated with the key */ public Object get(Object key) { if (!isDerived() || isActive()) { synchronized (_map) { return (_map.get(key)); } } else { ActiveMap parent=(ActiveMap)getParent(); Object ret=parent.get(key); if (getPredicate().evaluate(getContext(), ret)) { return (ret); } return (null); } } /** * {@inheritDoc} */ @Override protected void doInsert(Object key, Object value) { if (!isDerived() || isActive()) { synchronized (_map) { if (key != null) { _map.put(key, value); if (getItemExpiration() > 0) { _mapTimestamps.put(key, System.currentTimeMillis()); } } else { LOG.severe(java.util.PropertyResourceBundle.getBundle( "active-collection.Messages").getString("ACTIVE-COLLECTION-11")); } _readCopy = null; } inserted(key, value); } } /** * {@inheritDoc} */ @Override protected void doUpdate(Object key, Object value) { if (!isDerived() || isActive()) { synchronized (_map) { if (key != null) { _map.put(key, value); if (getItemExpiration() > 0) { _mapTimestamps.put(key, System.currentTimeMillis()); } } else { LOG.severe(java.util.PropertyResourceBundle.getBundle( "active-collection.Messages").getString("ACTIVE-COLLECTION-11")); } _readCopy = null; } updated(key, value); } } /** * {@inheritDoc} */ @Override protected void doRemove(Object key, Object value) { if (!isDerived() || isActive()) { synchronized (_map) { if (key != null) { value = _map.remove(key); if (getItemExpiration() > 0) { _mapTimestamps.remove(key); } } else { LOG.severe(java.util.PropertyResourceBundle.getBundle( "active-collection.Messages").getString("ACTIVE-COLLECTION-11")); } _readCopy = null; } removed(key, value); } } /** * {@inheritDoc} */ public Iterator<Object> iterator() { if (!isDerived() || isActive()) { synchronized (_map) { if (_readCopy == null) { _readCopy = new java.util.ArrayList<Object>(); for (Object key : _map.keySet()) { Object value=_map.get(key); _readCopy.add(new Entry(key, value)); } } return (_readCopy.iterator()); } } else { java.util.Map<Object,Object> derived=deriveContent(); java.util.List<Object> list=new java.util.ArrayList<Object>(); for (Object key : derived.keySet()) { Object value=derived.get(key); list.add(new Entry(key, value)); } return (list.iterator()); } } /** * {@inheritDoc} */ protected ActiveCollection derive(String name, ActiveCollectionContext context, Predicate predicate, java.util.Map<String,Object> properties) { return (new ActiveMap(name, this, context, predicate, properties)); } /** * {@inheritDoc} */ public java.util.List<Object> query(QuerySpec qs) { java.util.List<Object> ret=new java.util.ArrayList<Object>(); // TODO: Currently does not support any of the query // spec constraints for (Object obj : this) { ret.add(obj); } return (ret); } /** * {@inheritDoc} */ protected void cleanup() { if (!isDerived() || isActive()) { // TODO: Provide some separate cleanup policy class to enable // different policies to be used. For now just have a simple // directly implemented mechanism. if (getMaxItems() > 0) { synchronized (_map) { int num=getSize()-getMaxItems(); while (num > 0) { doRemove(0, null); num--; } } } if (getItemExpiration() > 0) { synchronized (_map) { // Calculate expiration time long expiration = System.currentTimeMillis()-getItemExpiration(); // Work through list backwards to determine if the entry // has expired for (int i=getSize()-1; i >= 0; i--) { if (_mapTimestamps.get(i) < expiration) { // TODO: Could do bulk remove and then // send notifications all at once??? doRemove(i, null); } } } } } } /** * {@inheritDoc} */ public boolean isEmpty() { if (!isDerived() || isActive()) { synchronized (_map) { return (_map.isEmpty()); } } else { java.util.Map<Object,Object> derived=deriveContent(); return (derived.isEmpty()); } } /** * {@inheritDoc} */ public int size() { return (getSize()); } /** * {@inheritDoc} */ public boolean containsKey(Object key) { if (!isDerived() || isActive()) { synchronized (_map) { return (_map.containsKey(key)); } } else { java.util.Map<Object,Object> derived=deriveContent(); return (derived.containsKey(key)); } } /** * {@inheritDoc} */ public boolean containsValue(Object value) { if (!isDerived() || isActive()) { synchronized (_map) { return (_map.containsValue(value)); } } else { java.util.Map<Object,Object> derived=deriveContent(); return (derived.containsValue(value)); } } /** * {@inheritDoc} */ public Object put(Object key, Object value) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public Object remove(Object key) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public void putAll(Map<? extends Object, ? extends Object> m) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public void clear() { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public Set<Object> keySet() { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public Collection<Object> values() { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public Set<java.util.Map.Entry<Object, Object>> entrySet() { throw new UnsupportedOperationException(); } /** * This class represents an entry in the map. * */ public class Entry { private Object _key=null; private Object _value=null; /** * This constructor initializes the key/value pair. * * @param key The key * @param value The value */ public Entry(Object key, Object value) { _key = key; _value = value; } /** * This method sets the key. * * @param key The key */ public void setKey(Object key) { _key = key; } /** * This method gets the key. * * @return The key */ public Object getKey() { return (_key); } /** * This method sets the value. * * @param value The value */ public void setValue(Object value) { _value = value; } /** * This method gets the value. * * @return The value */ public Object getValue() { return (_value); } } }