/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package com.espertech.esper.epl.join.table;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.epl.join.exec.composite.CompositeIndexEnterRemove;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.*;
/**
* For use when the index comprises of either two or more ranges or a unique key in combination with a range.
* Organizes into a TreeMap<key, TreeMap<key2, Set<EventBean>>, for short. The top level can also be just Map<MultiKeyUntyped, TreeMap...>.
* Expected at least either (A) one key and one range or (B) zero keys and 2 ranges.
* <p>
* An alternative implementatation could have been based on "TreeMap<ComparableMultiKey, Set<EventBean>>>", however the following implication arrive
* - not applicable for range-only lookups (since there the key can be the value itself
* - not applicable for multiple nested range as ordering not nested
* - each add/remove and lookup would also need to construct a key object.
*/
public class PropertyCompositeEventTable implements EventTable
{
private final CompositeIndexEnterRemove chain;
private final Class[] optKeyCoercedTypes;
private final Class[] optRangeCoercedTypes;
/**
* Index table (sorted and/or keyed, always nested).
*/
protected final Map<Object, Object> index;
public PropertyCompositeEventTable(boolean isHashKeyed, CompositeIndexEnterRemove chain, Class[] optKeyCoercedTypes, Class[] optRangeCoercedTypes)
{
this.chain = chain;
this.optKeyCoercedTypes = optKeyCoercedTypes;
this.optRangeCoercedTypes = optRangeCoercedTypes;
if (isHashKeyed) {
index = new HashMap<Object, Object>();
}
else {
index = new TreeMap<Object, Object>();
}
}
public Map<Object, Object> getIndex() {
return index;
}
public void addRemove(EventBean[] newData, EventBean[] oldData) {
add(newData);
remove(oldData);
}
/**
* Add an array of events. Same event instance is not added twice. Event properties should be immutable.
* Allow null passed instead of an empty array.
* @param events to add
* @throws IllegalArgumentException if the event was already existed in the index
*/
public void add(EventBean[] events)
{
if (events == null)
{
return;
}
for (EventBean theEvent : events)
{
add(theEvent);
}
}
/**
* Remove events.
* @param events to be removed, can be null instead of an empty array.
* @throws IllegalArgumentException when the event could not be removed as its not in the index
*/
public void remove(EventBean[] events)
{
if (events == null)
{
return;
}
for (EventBean theEvent : events)
{
remove(theEvent);
}
}
private void add(EventBean theEvent)
{
chain.enter(theEvent, index);
}
private void remove(EventBean theEvent)
{
chain.remove(theEvent, index);
}
public boolean isEmpty()
{
return index.isEmpty();
}
public Iterator<EventBean> iterator()
{
HashSet<EventBean> result = new LinkedHashSet<EventBean>();
chain.getAll(result, index);
return result.iterator();
}
public void clear()
{
index.clear();
}
public String toString() {
return toQueryPlan();
}
public String toQueryPlan()
{
return this.getClass().getName();
}
public Class[] getOptRangeCoercedTypes() {
return optRangeCoercedTypes;
}
public Class[] getOptKeyCoercedTypes() {
return optKeyCoercedTypes;
}
private static Log log = LogFactory.getLog(PropertyCompositeEventTable.class);
}