001/* 002 * Copyright (c) 2007-2016 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021package cascading.flow.planner.iso.subgraph.iterator; 022 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.List; 026import java.util.NoSuchElementException; 027import java.util.Set; 028 029import cascading.flow.FlowElement; 030import cascading.flow.planner.PlannerContext; 031import cascading.flow.planner.graph.ElementGraph; 032import cascading.flow.planner.iso.ElementAnnotation; 033import cascading.flow.planner.iso.expression.ElementCapture; 034import cascading.flow.planner.iso.expression.ExpressionGraph; 035import cascading.flow.planner.iso.finder.GraphFinder; 036import cascading.flow.planner.iso.finder.Match; 037import cascading.flow.planner.iso.subgraph.SubGraphIterator; 038import cascading.flow.planner.iso.transformer.ContractedTransformer; 039import cascading.flow.planner.iso.transformer.Transformed; 040import cascading.util.EnumMultiMap; 041 042import static cascading.flow.planner.graph.ElementGraphs.asSubGraph; 043import static cascading.util.Util.createIdentitySet; 044 045/** 046 * 047 */ 048public class ExpressionSubGraphIterator implements SubGraphIterator 049 { 050 private final PlannerContext plannerContext; 051 private final ElementGraph elementGraph; 052 053 private ContractedTransformer contractedTransformer; 054 private GraphFinder graphFinder; 055 056 private Set<FlowElement> elementExcludes = createIdentitySet(); 057 private ElementGraph contractedGraph; 058 private Transformed<ElementGraph> contractedTransformed; 059 060 private boolean firstOnly = false; // false will continue to accumulate around the primary 061 private Match match; 062 063 private List<Match> matches = new ArrayList<>(); 064 065 int count = 0; 066 067 public ExpressionSubGraphIterator( ExpressionGraph matchExpression, ElementGraph elementGraph ) 068 { 069 this( new PlannerContext(), matchExpression, elementGraph ); 070 } 071 072 public ExpressionSubGraphIterator( PlannerContext plannerContext, ExpressionGraph matchExpression, ElementGraph elementGraph ) 073 { 074 this( plannerContext, null, matchExpression, elementGraph ); 075 } 076 077 public ExpressionSubGraphIterator( PlannerContext plannerContext, ExpressionGraph contractionExpression, ExpressionGraph matchExpression, ElementGraph elementGraph ) 078 { 079 this( plannerContext, contractionExpression, matchExpression, false, elementGraph ); 080 } 081 082 public ExpressionSubGraphIterator( PlannerContext plannerContext, ExpressionGraph contractionExpression, ExpressionGraph matchExpression, ElementGraph elementGraph, Collection<FlowElement> elementExcludes ) 083 { 084 this( plannerContext, contractionExpression, matchExpression, false, elementGraph, elementExcludes ); 085 } 086 087 public ExpressionSubGraphIterator( PlannerContext plannerContext, ExpressionGraph contractionExpression, ExpressionGraph matchExpression, boolean firstOnly, ElementGraph elementGraph ) 088 { 089 this( plannerContext, contractionExpression, matchExpression, firstOnly, elementGraph, null ); 090 } 091 092 public ExpressionSubGraphIterator( PlannerContext plannerContext, ExpressionGraph contractionExpression, ExpressionGraph matchExpression, boolean firstOnly, ElementGraph elementGraph, Collection<FlowElement> elementExcludes ) 093 { 094 this.plannerContext = plannerContext; 095 this.firstOnly = firstOnly; 096 this.elementGraph = elementGraph; 097 098 if( elementExcludes != null ) 099 this.elementExcludes.addAll( elementExcludes ); 100 101 if( contractionExpression != null ) 102 contractedTransformer = new ContractedTransformer( contractionExpression ); 103 else 104 contractedGraph = elementGraph; 105 106 graphFinder = new GraphFinder( matchExpression ); 107 } 108 109 @Override 110 public ElementGraph getElementGraph() 111 { 112 return elementGraph; 113 } 114 115 public List<Match> getMatches() 116 { 117 return matches; 118 } 119 120 public ElementGraph getContractedGraph() 121 { 122 if( contractedGraph == null ) 123 { 124 contractedTransformed = contractedTransformer.transform( plannerContext, elementGraph ); 125 contractedGraph = contractedTransformed.getEndGraph(); 126 } 127 128 return contractedGraph; 129 } 130 131 public Match getLastMatch() 132 { 133 if( matches.isEmpty() ) 134 return null; 135 136 return matches.get( count - 1 ); 137 } 138 139 @Override 140 public EnumMultiMap getAnnotationMap( ElementAnnotation[] annotations ) 141 { 142 EnumMultiMap annotationsMap = new EnumMultiMap(); 143 144 if( annotations.length == 0 ) 145 return annotationsMap; 146 147 Match match = getLastMatch(); 148 149 for( ElementAnnotation annotation : annotations ) 150 annotationsMap.addAll( annotation.getAnnotation(), match.getCapturedElements( annotation.getCapture() ) ); 151 152 return annotationsMap; 153 } 154 155 @Override 156 public boolean hasNext() 157 { 158 if( match == null ) 159 { 160 match = graphFinder.findMatchesOnPrimary( plannerContext, getContractedGraph(), firstOnly, elementExcludes ); 161 162 if( match.foundMatch() ) 163 { 164 matches.add( match ); 165 elementExcludes.addAll( match.getCapturedElements( ElementCapture.Primary ) ); // idempotent 166 count++; 167 } 168 } 169 170 return match.foundMatch(); 171 } 172 173 @Override 174 public ElementGraph next() 175 { 176 try 177 { 178 if( !hasNext() ) 179 throw new NoSuchElementException(); 180 181 ElementGraph contractedMatchedGraph = match.getMatchedGraph(); 182 183 Set<FlowElement> excludes = getContractedGraph().vertexSetCopy(); 184 185 excludes.removeAll( contractedMatchedGraph.vertexSet() ); 186 187 return asSubGraph( elementGraph, contractedMatchedGraph, excludes ); 188 } 189 finally 190 { 191 match = null; 192 } 193 } 194 195 @Override 196 public void remove() 197 { 198 throw new UnsupportedOperationException(); 199 } 200 }