/** * Copyright 2013-2014 Recruit Technologies Co., Ltd. and contributors * (see CONTRIBUTORS.md) * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. A copy of the * License is distributed with this work in the LICENSE.md file. You may * also obtain a copy of the License from * * 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.gennai.gungnir.topology.operator; import static org.gennai.gungnir.GungnirConst.*; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; import org.gennai.gungnir.Period; import org.gennai.gungnir.topology.ConditionEvaluator; import org.gennai.gungnir.tuple.Condition; import org.gennai.gungnir.tuple.FieldAccessor; import org.gennai.gungnir.tuple.Field; import org.gennai.gungnir.tuple.GungnirTuple; import org.gennai.gungnir.utils.GungnirUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; @Operator.Description(name = "FILTER_GROUP", parameterNames = {"expire", "stateField", "conditions"}) public class FilterGroupOperator extends BaseOperator implements ExecOperator { private static final long serialVersionUID = SERIAL_VERSION_UID; private static final Logger LOG = LoggerFactory.getLogger(FilterGroupOperator.class); private Period expire; private FieldAccessor stateField; private Condition[] conditions; private int expireSecs; private int[] keepTimes; public FilterGroupOperator(Period expire, FieldAccessor stateField, Condition... conditions) { super(); this.expire = expire; this.stateField = stateField; this.conditions = conditions; } public FilterGroupOperator(Period expire, Condition... conditions) { this(expire, null, conditions); } private FilterGroupOperator(FilterGroupOperator c) { super(c); this.expire = c.expire; this.stateField = c.stateField; this.conditions = c.conditions; } @Override protected void prepare() { expireSecs = expire.toSeconds(); keepTimes = new int[conditions.length]; } @Override public void execute(GungnirTuple tuple) { if (LOG.isDebugEnabled()) { LOG.debug("execute({} {}) {}", getContext().getTopologyId(), getName(), tuple); } int now = GungnirUtils.currentTimeSecs(); for (int i = 0; i < keepTimes.length; i++) { if (keepTimes[i] > 0) { if (now > keepTimes[i]) { keepTimes[i] = 0; if (LOG.isDebugEnabled()) { LOG.debug("Expired condition {}", conditions[i]); } } } } for (int i = 0; i < conditions.length; i++) { if (ConditionEvaluator.isKeep(conditions[i], tuple)) { keepTimes[i] = now + expireSecs; if (LOG.isDebugEnabled()) { LOG.debug("Keep condition {}", conditions[i]); } } } boolean isKeep = true; for (int time : keepTimes) { if (time == 0) { isKeep = false; break; } } if (isKeep) { if (LOG.isDebugEnabled()) { LOG.debug("Keep {}", getName()); } if (stateField != null) { List<Date> status = Lists.newArrayListWithCapacity(keepTimes.length); for (int time : keepTimes) { status.add(new Date(TimeUnit.SECONDS.toMillis(time))); } tuple.getTupleValues().getValues().add(status); } dispatch(tuple.getTupleValues()); for (int i = 0; i < keepTimes.length; i++) { keepTimes[0] = 0; } } } @Override public List<Field> getOutputFields() { if (stateField != null) { List<Field> fields = Lists.newArrayListWithCapacity(2); fields.add(new FieldAccessor("*")); fields.add(stateField); return fields; } else { return null; } } @Override public FilterGroupOperator clone() { return new FilterGroupOperator(this); } }