/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* 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.expression.funcs;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventPropertyGetter;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.PropertyAccessException;
import com.espertech.esper.epl.expression.core.*;
import com.espertech.esper.event.vaevent.VariantEvent;
import com.espertech.esper.filter.FilterSpecLookupable;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import java.io.StringWriter;
import java.util.Map;
/**
* Represents the TYPEOF(a) function is an expression tree.
*/
public class ExprTypeofNode extends ExprNodeBase implements ExprFilterOptimizableNode {
private static final long serialVersionUID = -612634538694877204L;
private transient ExprEvaluator evaluator;
/**
* Ctor.
*/
public ExprTypeofNode() {
}
public ExprEvaluator getExprEvaluator() {
return evaluator;
}
public Map<String, Object> getEventType() {
return null;
}
public ExprNode validate(ExprValidationContext validationContext) throws ExprValidationException {
if (this.getChildNodes().length != 1) {
throw new ExprValidationException("Typeof node must have 1 child expression node supplying the expression to test");
}
if (this.getChildNodes()[0] instanceof ExprStreamUnderlyingNode) {
ExprStreamUnderlyingNode stream = (ExprStreamUnderlyingNode) getChildNodes()[0];
evaluator = new StreamEventTypeEval(stream.getStreamId());
return null;
}
if (this.getChildNodes()[0] instanceof ExprIdentNode) {
ExprIdentNode ident = (ExprIdentNode) getChildNodes()[0];
int streamNum = validationContext.getStreamTypeService().getStreamNumForStreamName(ident.getFullUnresolvedName());
if (streamNum != -1) {
evaluator = new StreamEventTypeEval(streamNum);
return null;
}
EventType eventType = validationContext.getStreamTypeService().getEventTypes()[ident.getStreamId()];
if (eventType.getFragmentType(ident.getResolvedPropertyName()) != null) {
evaluator = new FragmentTypeEval(ident.getStreamId(), eventType, ident.getResolvedPropertyName());
return null;
}
}
evaluator = new InnerEvaluator(this.getChildNodes()[0].getExprEvaluator());
return null;
}
public boolean isConstantResult() {
return false;
}
public Class getType() {
return String.class;
}
public boolean getFilterLookupEligible() {
return true;
}
public FilterSpecLookupable getFilterLookupable() {
EventPropertyGetter getter = new EventPropertyGetter() {
public Object get(EventBean eventBean) throws PropertyAccessException {
return eventBean.getEventType().getName();
}
public boolean isExistsProperty(EventBean eventBean) {
return true;
}
public Object getFragment(EventBean eventBean) throws PropertyAccessException {
return null;
}
};
return new FilterSpecLookupable(ExprNodeUtility.toExpressionStringMinPrecedenceSafe(this), getter, String.class, true);
}
public void toPrecedenceFreeEPL(StringWriter writer) {
writer.append("typeof(");
this.getChildNodes()[0].toEPL(writer, ExprPrecedenceEnum.MINIMUM);
writer.append(')');
}
public ExprPrecedenceEnum getPrecedence() {
return ExprPrecedenceEnum.UNARY;
}
public boolean equalsNode(ExprNode node, boolean ignoreStreamPrefix) {
return node instanceof ExprTypeofNode;
}
public static class StreamEventTypeEval implements ExprEvaluator {
private final int streamNum;
public StreamEventTypeEval(int streamNum) {
this.streamNum = streamNum;
}
@Override
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().qExprTypeof();
}
EventBean theEvent = eventsPerStream[streamNum];
if (theEvent == null) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(null);
}
return null;
}
if (theEvent instanceof VariantEvent) {
String typeName = ((VariantEvent) theEvent).getUnderlyingEventBean().getEventType().getName();
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(typeName);
}
return typeName;
}
if (InstrumentationHelper.ENABLED) {
String typeName = theEvent.getEventType().getName();
InstrumentationHelper.get().aExprTypeof(typeName);
return typeName;
}
return theEvent.getEventType().getName();
}
@Override
public Class getType() {
return String.class;
}
}
public static class FragmentTypeEval implements ExprEvaluator {
private final int streamId;
private final EventPropertyGetter getter;
private final String fragmentType;
public FragmentTypeEval(int streamId, EventType eventType, String resolvedPropertyName) {
this.streamId = streamId;
getter = eventType.getGetter(resolvedPropertyName);
fragmentType = eventType.getFragmentType(resolvedPropertyName).getFragmentType().getName();
}
@Override
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().qExprTypeof();
}
EventBean theEvent = eventsPerStream[streamId];
if (theEvent == null) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(null);
}
return null;
}
Object fragment = getter.getFragment(theEvent);
if (fragment == null) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(null);
}
return null;
}
if (fragment instanceof EventBean) {
EventBean bean = (EventBean) fragment;
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(bean.getEventType().getName());
}
return bean.getEventType().getName();
}
if (fragment.getClass().isArray()) {
String type = fragmentType + "[]";
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(type);
}
return type;
}
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(null);
}
return null;
}
@Override
public Class getType() {
return String.class;
}
}
private static class InnerEvaluator implements ExprEvaluator {
private final ExprEvaluator evaluator;
public InnerEvaluator(ExprEvaluator evaluator) {
this.evaluator = evaluator;
}
@Override
public Class getType() {
return String.class;
}
@Override
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().qExprTypeof();
}
Object result = evaluator.evaluate(eventsPerStream, isNewData, context);
if (result == null) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(null);
}
return null;
}
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().aExprTypeof(result.getClass().getSimpleName());
}
return result.getClass().getSimpleName();
}
}
}