/**
* 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 com.huawei.streaming.expression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.huawei.streaming.common.StreamClassUtil;
import com.huawei.streaming.event.IEvent;
import com.huawei.streaming.exception.ErrorCode;
import com.huawei.streaming.exception.StreamingException;
import com.huawei.streaming.window.AbstractAccessService;
import com.huawei.streaming.window.IRandomAccessByIndex;
import com.huawei.streaming.window.IRelativeAccessByEventAndIndex;
import com.huawei.streaming.window.RandomAccessByIndexService;
import com.huawei.streaming.window.RelativeAccessByEventAndIndexService;
/**
* <previous表达式,获取窗口中第几条数据中的指定属性的值>
* <如果包含Previous Expression,则必须包含窗口(不支持窗口的叠加,仅能有一个窗口)
* 语法如下:previous(index, property)。其中index为索引信息,property为事件中指定属性名。>
*
*/
public class PreviousExpression implements IExpression
{
/**
* 序列化ID
*/
private static final long serialVersionUID = 8398398053090322356L;
/**
* 日志对象
*/
private static final Logger LOG = LoggerFactory.getLogger(PreviousExpression.class);
/**
* 返回结果类型
*/
private Class< ? > resultType;
/**
* 从窗口缓存获取事件服务
*/
private RandomAccessByIndexService randomAccessService;
/**
* 从窗口缓存获取事件服务
*/
private RelativeAccessByEventAndIndexService relativeAccessService;
/**
* 索引表达式
*/
private IExpression indexExpr;
/**
* 属性表达式
*/
private IExpression proExpr;
private int streamIndex;
/**
* <默认构造函数>
*@param indexExpr 索引表达式
*@param proExpr 属性表达式
*@throws StreamingException 表达式构建异常
*/
public PreviousExpression(IExpression indexExpr, IExpression proExpr)
throws StreamingException
{
if (indexExpr == null || proExpr == null)
{
LOG.error("Arguments in '{}' operator is null.", this.getClass().getName());
StreamingException exception = new StreamingException(ErrorCode.UNKNOWN_SERVER_COMMON_ERROR);
throw exception;
}
Class< ? > indexType = indexExpr.getType();
if (!StreamClassUtil.isNumberic(indexType))
{
StreamingException exception = new StreamingException(ErrorCode.FUNCTION_PREVIOUS_PROPERTYVALUE_EXPRSSION);
LOG.error(ErrorCode.FUNCTION_PREVIOUS_PROPERTYVALUE_EXPRSSION.getFullMessage(), exception);
throw exception;
}
this.indexExpr = indexExpr;
this.proExpr = proExpr;
if (proExpr instanceof PropertyValueExpression)
{
this.streamIndex = ((PropertyValueExpression)proExpr).getStreamIndex();
}
resultType = proExpr.getType();
}
/**
* <设置Previous表达式访问窗口数据服务>
* <设置Previous表达式访问窗口数据服务>
*/
public void setService(AbstractAccessService service)
{
if (service == null)
{
String msg = "Service is NULl.";
LOG.error(msg);
throw new IllegalArgumentException(msg);
}
if (service instanceof RandomAccessByIndexService)
{
this.randomAccessService = (RandomAccessByIndexService)service;
}
if (service instanceof RelativeAccessByEventAndIndexService)
{
this.relativeAccessService = (RelativeAccessByEventAndIndexService)service;
}
}
/** {@inheritDoc} */
@Override
public Object evaluate(IEvent theEvent)
{
Object value = indexExpr.evaluate(theEvent);
if (value == null)
{
return null;
}
int indexValue = checkIndexValue(value);
return getProValue(theEvent, indexValue);
}
private Object getProValue(IEvent theEvent, int indexValue)
{
if (randomAccessService != null)
{
IRandomAccessByIndex randomAccess = randomAccessService.getAccessor();
if(randomAccess == null)
{
return null;
}
IEvent indexEvent = randomAccess.getEvent(indexValue, true);
if (indexEvent == null)
{
return null;
}
return proExpr.evaluate(indexEvent);
}
if (relativeAccessService != null)
{
IRelativeAccessByEventAndIndex relativeAccess = relativeAccessService.getAccessor();
if(relativeAccess == null)
{
return null;
}
IEvent indexEvent = relativeAccess.getEvent(theEvent, indexValue);
if (indexEvent == null)
{
return null;
}
return proExpr.evaluate(indexEvent);
}
return null;
}
private int checkIndexValue(Object value)
{
if (!(value instanceof Number))
{
String msg = "Previous Expression requires an integer index parameter or expression.";
LOG.error(msg);
throw new IllegalArgumentException(msg);
}
Number indexValue = (Number)value;
if (StreamClassUtil.isFloatingPointNumber(indexValue))
{
String msg = "Previous Expression requires an integer index parameter or expression.";
LOG.error(msg);
throw new IllegalArgumentException(msg);
}
return indexValue.intValue();
}
/** {@inheritDoc} */
@Override
public Object evaluate(IEvent[] eventsPerStream)
{
Object value = indexExpr.evaluate(eventsPerStream);
if (value == null)
{
return null;
}
int indexValue = checkIndexValue(value);
return getProValue(eventsPerStream, indexValue);
}
private Object getProValue(IEvent[] eventsPerStream, int indexValue)
{
if (randomAccessService != null)
{
IRandomAccessByIndex randomAccess = randomAccessService.getAccessor();
if(randomAccess == null)
{
return null;
}
IEvent indexEvent = randomAccess.getEvent(indexValue, true);
if (indexEvent == null)
{
return null;
}
return proExpr.evaluate(indexEvent);
}
if (relativeAccessService != null)
{
IRelativeAccessByEventAndIndex relativeAccess = relativeAccessService.getAccessor();
if(relativeAccess == null)
{
return null;
}
IEvent indexEvent = relativeAccess.getEvent(eventsPerStream[streamIndex], indexValue);
if (indexEvent == null)
{
return null;
}
IEvent originalEvent = eventsPerStream[streamIndex];
eventsPerStream[streamIndex] = indexEvent;
Object evaluteValue = proExpr.evaluate(eventsPerStream);
eventsPerStream[streamIndex] = originalEvent;
return evaluteValue;
}
return null;
}
/** {@inheritDoc} */
@Override
public Class< ? > getType()
{
return resultType;
}
public IExpression getProExpr()
{
return proExpr;
}
public IExpression getIndexExpr()
{
return indexExpr;
}
}