/** * 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.ql.analysis.analyzer; import static org.gennai.gungnir.ql.analysis.GungnirLexer.*; import java.util.List; import org.gennai.gungnir.GungnirTopologyException; import org.gennai.gungnir.Period; import org.gennai.gungnir.ql.analysis.ASTNode; import org.gennai.gungnir.ql.analysis.SemanticAnalyzeException; import org.gennai.gungnir.ql.stream.GroupedStream; import org.gennai.gungnir.ql.stream.SingleStream; import org.gennai.gungnir.ql.stream.Stream; import org.gennai.gungnir.ql.stream.TupleJoinStreamBuilder.JoinToTupleDeclarer; import org.gennai.gungnir.topology.processor.InMemoryTtlCacheProcessor; import org.gennai.gungnir.topology.processor.Processor; import org.gennai.gungnir.topology.processor.TtlCacheProcessor; import org.gennai.gungnir.tuple.Condition; import org.gennai.gungnir.tuple.FieldAccessor; import org.gennai.gungnir.tuple.TupleAccessor; import org.gennai.gungnir.tuple.schema.Schema; import com.google.common.collect.Lists; public class FromStreamsClauseAnalyzer { private FromClauseAnalyzer fromClauseAnalyzer; public FromStreamsClauseAnalyzer(FromClauseAnalyzer fromClauseAnalyzer) { this.fromClauseAnalyzer = fromClauseAnalyzer; } private TupleAccessor[] tupleNamesAnalyze(ASTNode node) throws SemanticAnalyzeException { if (node.getChildCount() == 0) { return null; } TupleAccessor[] tuples = new TupleAccessor[node.getChildCount()]; for (int i = 0; i < node.getChildCount(); i++) { String tupleName = fromClauseAnalyzer.getSemanticAnalyzer().analyzeByAnalyzer(node.getChild(i)); Schema schema = fromClauseAnalyzer.getSemanticAnalyzer().getSchemaRegistry().get(tupleName); if (schema != null) { tupleName = schema.getSchemaName(); } tuples[i] = new TupleAccessor(tupleName); } return tuples; } private static class JoinStreamDeclare { private Stream joinStream; private Condition joinCondition; } private JoinStreamDeclare joinStreamExprAnalyze(ASTNode node, Stream stream) throws SemanticAnalyzeException, GungnirTopologyException { JoinStreamDeclare declare = new JoinStreamDeclare(); String streamName = fromClauseAnalyzer.getSemanticAnalyzer().analyzeByAnalyzer(node.getChild(0)); Stream s = fromClauseAnalyzer.getSemanticAnalyzer().getStream(streamName); if (s == null) { throw new SemanticAnalyzeException("Not exists stream '" + streamName + "'"); } if (s.getClass() != stream.getClass()) { throw new SemanticAnalyzeException("Can't merge stream and grouped stream " + s); } else { if (s instanceof GroupedStream<?>) { if (!((GroupedStream<?>) s).getGroupFields().equals( ((GroupedStream<?>) stream).getGroupFields())) { throw new SemanticAnalyzeException("Can't merge stream grouped by different fields " + s); } } } String tupleName = fromClauseAnalyzer.getSemanticAnalyzer().analyzeByAnalyzer(node.getChild(1)); declare.joinStream = s.select(new TupleAccessor(tupleName)); Condition joinCondition = fromClauseAnalyzer.getSemanticAnalyzer().analyzeByAnalyzer(node.getChild(2)); declare.joinCondition = joinCondition; return declare; } private List<JoinStreamDeclare> joinStreamExprsAnalyze(ASTNode node, Stream stream) throws SemanticAnalyzeException, GungnirTopologyException { List<JoinStreamDeclare> declares = Lists.newArrayListWithCapacity(node.getChildCount()); for (int i = 0; i < node.getChildCount(); i++) { declares.add(joinStreamExprAnalyze(node.getChild(i), stream)); } return declares; } private static class JoinStreamsDeclare { private Stream fromStream; private List<JoinStreamDeclare> streamDeclares; private FieldAccessor[] toFields; private TupleAccessor toTuple; private Period expire; private TtlCacheProcessor processor; } @SuppressWarnings("unchecked") public Stream analyze(ASTNode node) throws SemanticAnalyzeException, GungnirTopologyException { List<Stream> streams = Lists.newArrayList(); List<JoinStreamsDeclare> streamsDeclares = null; Stream stream = null; for (int i = 0; i < node.getChild(0).getChildCount(); i++) { ASTNode child = node.getChild(0).getChild(i); String streamName = fromClauseAnalyzer.getSemanticAnalyzer().analyzeByAnalyzer(child.getChild(0)); Stream s = fromClauseAnalyzer.getSemanticAnalyzer().getStream(streamName); if (s == null) { throw new SemanticAnalyzeException("Not exists stream '" + streamName + "'"); } if (stream != null) { if (s.getClass() != stream.getClass()) { throw new SemanticAnalyzeException("Can't join stream and grouped stream " + stream); } else { if (s instanceof GroupedStream<?>) { if (!((GroupedStream<?>) s).getGroupFields().equals( ((GroupedStream<?>) stream).getGroupFields())) { throw new SemanticAnalyzeException("Can't merge stream grouped by different fields " + s); } } } } stream = s; if (child.getChild(1) != null) { if (child.getChild(1).getType() == TOK_TUPLE_NAMES) { TupleAccessor[] tuples = tupleNamesAnalyze(child.getChild(1)); if (tuples != null) { stream = stream.select(tuples); } } else { String tupleName = fromClauseAnalyzer.getSemanticAnalyzer().analyzeByAnalyzer(child.getChild(1)); stream = stream.select(new TupleAccessor(tupleName)); } } if (child.getChild(2) != null && child.getChild(2).getType() == TOK_JOIN_STREAM_EXPRS) { List<JoinStreamDeclare> declares = joinStreamExprsAnalyze(child.getChild(2), stream); JoinStreamsDeclare schemasDeclare = new JoinStreamsDeclare(); schemasDeclare.fromStream = stream; schemasDeclare.streamDeclares = declares; schemasDeclare.toFields = fromClauseAnalyzer.tupleJoinToExprAnalyze(child.getChild(3)); schemasDeclare.expire = fromClauseAnalyzer.getSemanticAnalyzer() .analyzeByAnalyzer(child.getChild(4)); String toTupleName; if (child.getChild(5).getType() == TOK_PROCESSOR) { Processor p = fromClauseAnalyzer.getSemanticAnalyzer() .analyzeByAnalyzer(child.getChild(5)); if (p instanceof TtlCacheProcessor) { schemasDeclare.processor = (TtlCacheProcessor) p; } else { throw new SemanticAnalyzeException("Processor isn't cache processor '" + p + "'"); } toTupleName = fromClauseAnalyzer.getSemanticAnalyzer() .analyzeByAnalyzer(child.getChild(6)); } else { schemasDeclare.processor = new InMemoryTtlCacheProcessor(); toTupleName = fromClauseAnalyzer.getSemanticAnalyzer() .analyzeByAnalyzer(child.getChild(5)); } schemasDeclare.toTuple = new TupleAccessor(toTupleName); fromClauseAnalyzer.getSemanticAnalyzer().getStreamTuples().add(toTupleName); if (streamsDeclares == null) { streamsDeclares = Lists.newArrayList(); } streamsDeclares.add(schemasDeclare); } else { String aliasName = fromClauseAnalyzer.getSemanticAnalyzer().analyzeByAnalyzer(child.getChild(2)); if (aliasName != null) { stream = stream.alias(new TupleAccessor(aliasName)); fromClauseAnalyzer.getSemanticAnalyzer().getStreamTuples().add(aliasName); } streams.add(stream); } } if (streams.size() > 0) { stream = fromClauseAnalyzer.getSemanticAnalyzer().getTopology() .from(streams.toArray(new Stream[0])); } if (streamsDeclares == null) { return stream; } else { for (JoinStreamsDeclare streamsDeclare : streamsDeclares) { if (stream instanceof SingleStream) { JoinToTupleDeclarer<SingleStream> joinToTupleDeclarer = ((SingleStream) streamsDeclare.fromStream).join( (SingleStream) streamsDeclare.streamDeclares.get(0).joinStream, streamsDeclare.streamDeclares.get(0).joinCondition); for (int i = 1; i < streamsDeclare.streamDeclares.size(); i++) { joinToTupleDeclarer = joinToTupleDeclarer.join( ((SingleStream) streamsDeclare.streamDeclares.get(i).joinStream), streamsDeclare.streamDeclares.get(i).joinCondition); } SingleStream joinedStream = joinToTupleDeclarer.to(streamsDeclare.toTuple, streamsDeclare.toFields) .expire(streamsDeclare.expire).using(streamsDeclare.processor).build(); streams.add(joinedStream); } else { JoinToTupleDeclarer<GroupedStream<Stream>> joinToTupleDeclarer = ((GroupedStream<Stream>) streamsDeclare.fromStream).join( (GroupedStream<Stream>) streamsDeclare.streamDeclares.get(0).joinStream, streamsDeclare.streamDeclares.get(0).joinCondition); for (int i = 1; i < streamsDeclare.streamDeclares.size(); i++) { joinToTupleDeclarer = joinToTupleDeclarer.join( ((GroupedStream<Stream>) streamsDeclare.streamDeclares.get(0).joinStream), streamsDeclare.streamDeclares.get(0).joinCondition); } GroupedStream<Stream> joinedStream = joinToTupleDeclarer.to(streamsDeclare.toTuple, streamsDeclare.toFields) .expire(streamsDeclare.expire).using(streamsDeclare.processor).build(); streams.add(joinedStream); } } return fromClauseAnalyzer.getSemanticAnalyzer().getTopology() .from(streams.toArray(new Stream[0])); } } }