/**
* 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.processor;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.huawei.streaming.common.MultiKey;
import com.huawei.streaming.common.Pair;
import com.huawei.streaming.event.IEvent;
import com.huawei.streaming.lock.ILock;
import com.huawei.streaming.lock.LockImpl;
import com.huawei.streaming.output.IOutput;
import com.huawei.streaming.output.OutputType;
import com.huawei.streaming.process.join.IJoinComposer;
import com.huawei.streaming.process.join.IJoinSetProcessor;
import com.huawei.streaming.process.join.JoinFilterProcessor;
/**
* 两个数据流的Join操作
* <功能详细描述>
*
*/
public class JoinProcessor extends ProcessorImpl
{
/**
* 序列化id
*/
private static final long serialVersionUID = -3565183563328255491L;
private static final Logger LOG = LoggerFactory.getLogger(JoinProcessor.class);
private IJoinComposer joinComposer;
private JoinFilterProcessor joinFilter;
private IJoinSetProcessor joinSetProcess;
private final IOutput output;
private final OutputType outputType;
private String[] streamNames;
private int streamNum;
private boolean unidirectional = false;
private int uniStreamIndex = 0;
private boolean selfJoin = false;
private boolean synFlag = false;
/**
* 锁对象,当前线程与定时器线程访问数据时需要先获取锁。
*/
private ILock lock = new LockImpl();
/**
*
* <默认构造函数>
*@param comps Join组合处理
*@param names Join流名称
*@param filter Join过滤处理
*@param setProcess Join结果选择处理
*@param out Join输出对象
*@param type Join输出类型
*/
public JoinProcessor(IJoinComposer comps, String[] names, JoinFilterProcessor filter, IJoinSetProcessor setProcess,
IOutput out, OutputType type)
{
LOG.debug("Initiate JoinProcessor.");
if (null == comps)
{
LOG.error("The join composer is null.");
throw new RuntimeException("The join composer is null.");
}
if (null == setProcess)
{
LOG.error("The selct process is null.");
throw new RuntimeException("The selct process is null.");
}
if (null == out)
{
LOG.error("The output process is null.");
throw new RuntimeException("The output process is null.");
}
if (names.length != comps.getStreamsSize())
{
LOG.error("The streams number are not match. Composer size is {}, and stream names size is {}.",
comps.getStreamsSize(),
names.length);
throw new RuntimeException("The streams number are not match.");
}
this.joinComposer = comps;
this.joinFilter = filter;
this.joinSetProcess = setProcess;
this.streamNames = names;
this.streamNum = names.length;
this.output = out;
if (null != type)
{
this.outputType = type;
}
else
{
this.outputType = OutputType.I;
}
}
/**
* 设置是否为单向
* <功能详细描述>
*/
public void setUnidirectional(Boolean uni)
{
this.unidirectional = uni;
}
/**
* 设置单向流索引
* <功能详细描述>
*/
public void setUniStreamIndex(int index)
{
this.uniStreamIndex = index;
}
/**
* 设置是否单流JOIN
* <功能详细描述>
*/
public void setSelfJoin(Boolean self)
{
this.selfJoin = self;
}
/**
* {@inheritDoc}
*/
@Override
public void process(IEvent[] newData, IEvent[] oldData)
{
IEvent event = getCurrentEvent(newData, oldData);
if (null == event)
{
return;
}
try
{
lock.lock();
//获得当前事件所属事件流的下标
int streamIndex = getStreamIndex(event);
//将更新数据按数据流组织
IEvent[][] newDataPerStream = new IEvent[streamNum][];
IEvent[][] oldDataPerStream = new IEvent[streamNum][];
newDataPerStream[streamIndex] = newData;
oldDataPerStream[streamIndex] = oldData;
//维护多个流中的窗口有效数据
joinComposer.maintainData(newDataPerStream, oldDataPerStream);
/**
* 如果为单流,通过开关保证数据都进两个窗口后进行JOIN操作,只进入一个窗口,返回
*/
if (selfJoin)
{
if (synFlag)
{
synFlag = false;
}
else
{
synFlag = true;
return;
}
}
//对事件JOIN
Pair<Set<MultiKey>, Set<MultiKey>> composedEvents = null;
//如果为单向
if (unidirectional)
{
if (!selfJoin)
{
if (streamIndex != uniStreamIndex)
{
return;
}
}
}
composedEvents = joinComposer.join(newDataPerStream, oldDataPerStream);
/*
* 空时间判断,防止join之后产生空值
*/
/*switch (outputType)
{
case I:
if (composedEvents.getFirst() == null || composedEvents.getFirst().size() == 0)
{
return;
}
break;
case R:
if (composedEvents.getSecond() == null || composedEvents.getSecond().size() == 0)
{
return;
}
break;
case IR:
default:
if ((composedEvents.getFirst() == null || composedEvents.getFirst().size() == 0)
&& (composedEvents.getSecond() == null || composedEvents.getSecond().size() == 0))
{
return;
}
break;
}
//对JOIN结果进行过滤
if (null != joinFilter)
{
switch (outputType)
{
case I:
joinFilter.filter(composedEvents.getFirst());
break;
case R:
joinFilter.filter(composedEvents.getSecond());
break;
case IR:
joinFilter.filter(composedEvents.getFirst());
joinFilter.filter(composedEvents.getSecond());
break;
default:
LOG.error("Not supported. output type={}", outputType);
throw new RuntimeException("Not supported.");
}
}
//对过滤结果进行取值
IEvent[] newResult = null;
IEvent[] oldResult = null;
switch (outputType)
{
case I:
newResult = joinSelect.process(composedEvents.getFirst());
break;
case R:
oldResult = joinSelect.process(composedEvents.getSecond());
break;
case IR:
default:
newResult = joinSelect.process(composedEvents.getFirst());
oldResult = joinSelect.process(composedEvents.getSecond());
}
Pair<IEvent[], IEvent[]> out = new Pair<IEvent[], IEvent[]>(newResult, oldResult);
*/
if (null != joinFilter)
{
joinFilter.filter(composedEvents.getFirst());
joinFilter.filter(composedEvents.getSecond());
}
Pair<IEvent[], IEvent[]> out =
joinSetProcess.processJoinResult(composedEvents.getFirst(), composedEvents.getSecond(), outputType);
output.output(out);
}
finally
{
if (lock.isLocked())
{
lock.unlock();
}
}
}
/**
* <返回事件对应类型在Join操作中索引>
*/
private int getStreamIndex(IEvent event)
{
String name = event.getStreamName();
for (int i = 0; i < streamNum; i++)
{
if (StringUtils.equals(name, streamNames[i]))
{
return i;
}
}
LOG.error("Wrong stream name. name={}.", name);
throw new RuntimeException("Wrong stream name.");
}
/**
* <从新事件和旧事件中获取事件,如果新事件不为空,则从新事件获取,否则从旧事件中获取>
*/
private IEvent getCurrentEvent(IEvent[] newData, IEvent[] oldData)
{
if (null == newData && null == oldData)
{
return null;
}
IEvent event = null;
if (null != newData)
{
event = newData[0];
if (null != event)
{
return event;
}
}
return oldData[0];
}
}