001/* 002 * Copyright (c) 2016-2017 Chris K Wensel <chris@wensel.net>. All Rights Reserved. 003 * Copyright (c) 2007-2017 Xplenty, Inc. All Rights Reserved. 004 * 005 * Project and contact information: http://www.cascading.org/ 006 * 007 * This file is part of the Cascading project. 008 * 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 */ 021 022package cascading.flow.planner.graph; 023 024import java.io.Serializable; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.IdentityHashMap; 028import java.util.List; 029import java.util.Set; 030 031import cascading.flow.FlowElement; 032import cascading.flow.planner.Scope; 033import cascading.util.Util; 034import org.jgrapht.DirectedGraph; 035import org.jgrapht.Graph; 036import org.jgrapht.Graphs; 037import org.jgrapht.graph.SimpleDirectedGraph; 038 039/** 040 * 041 */ 042public abstract class BaseElementGraph implements ElementGraph, Serializable 043 { 044 public static final ElementGraph NULL = new BaseElementGraph( new SimpleDirectedGraph<>( Scope.class ) ) 045 { 046 @Override 047 public ElementGraph copyElementGraph() 048 { 049 return null; 050 } 051 }; 052 053 protected Graph<FlowElement, Scope> graph; 054 055 public BaseElementGraph() 056 { 057 } 058 059 public BaseElementGraph( DirectedGraph<FlowElement, Scope> graph ) 060 { 061 this.graph = graph; 062 } 063 064 protected void copyFrom( ElementGraph elementGraph ) 065 { 066 Graphs.addAllVertices( graph, elementGraph.vertexSet() ); 067 Graphs.addAllEdges( graph, ElementGraphs.directed( elementGraph ), elementGraph.edgeSet() ); 068 } 069 070 public boolean containsEdge( FlowElement sourceVertex, FlowElement targetVertex ) 071 { 072 return graph.containsEdge( sourceVertex, targetVertex ); 073 } 074 075 public boolean removeAllEdges( Collection<? extends Scope> edges ) 076 { 077 return graph.removeAllEdges( edges ); 078 } 079 080 public Set<Scope> removeAllEdges( FlowElement sourceVertex, FlowElement targetVertex ) 081 { 082 return graph.removeAllEdges( sourceVertex, targetVertex ); 083 } 084 085 public boolean removeAllVertices( Collection<? extends FlowElement> vertices ) 086 { 087 return graph.removeAllVertices( vertices ); 088 } 089 090 public Set<Scope> getAllEdges( FlowElement sourceVertex, FlowElement targetVertex ) 091 { 092 return graph.getAllEdges( sourceVertex, targetVertex ); 093 } 094 095 public Scope getEdge( FlowElement sourceVertex, FlowElement targetVertex ) 096 { 097 return graph.getEdge( sourceVertex, targetVertex ); 098 } 099 100 public Scope addEdge( FlowElement sourceVertex, FlowElement targetVertex ) 101 { 102// prevent multiple edges from head or to tail 103 if( !allowMultipleExtentEdges() && ( sourceVertex == Extent.head || targetVertex == Extent.tail ) && graph.containsEdge( sourceVertex, targetVertex ) ) 104 return graph.getEdge( sourceVertex, targetVertex ); 105 106 return graph.addEdge( sourceVertex, targetVertex ); 107 } 108 109 public boolean addEdge( FlowElement sourceVertex, FlowElement targetVertex, Scope scope ) 110 { 111 // prevent multiple edges from head or to tail 112 if( !allowMultipleExtentEdges() && ( sourceVertex == Extent.head || targetVertex == Extent.tail ) && graph.containsEdge( sourceVertex, targetVertex ) ) 113 return true; 114 115 return graph.addEdge( sourceVertex, targetVertex, scope ); 116 } 117 118 protected boolean allowMultipleExtentEdges() 119 { 120 return true; 121 } 122 123 @Override 124 public boolean addHeadVertex( FlowElement flowElement ) 125 { 126 if( !graph.containsVertex( Extent.head ) ) 127 graph.addVertex( Extent.head ); 128 129 if( flowElement == Extent.head ) 130 return false; 131 132 boolean result = true; 133 134 if( !graph.containsVertex( flowElement ) ) 135 result = graph.addVertex( flowElement ); 136 137 return result && graph.addEdge( Extent.head, flowElement ) != null; 138 } 139 140 @Override 141 public boolean addTailVertex( FlowElement flowElement ) 142 { 143 if( !graph.containsVertex( Extent.tail ) ) 144 graph.addVertex( Extent.tail ); 145 146 if( flowElement == Extent.tail ) 147 return false; 148 149 boolean result = true; 150 151 if( !graph.containsVertex( flowElement ) ) 152 result = graph.addVertex( flowElement ); 153 154 return result && graph.addEdge( flowElement, Extent.tail ) != null; 155 } 156 157 public boolean addVertex( FlowElement flowElement ) 158 { 159 return graph.addVertex( flowElement ); 160 } 161 162 public FlowElement getEdgeSource( Scope scope ) 163 { 164 return graph.getEdgeSource( scope ); 165 } 166 167 public FlowElement getEdgeTarget( Scope scope ) 168 { 169 return graph.getEdgeTarget( scope ); 170 } 171 172 public boolean containsEdge( Scope scope ) 173 { 174 return graph.containsEdge( scope ); 175 } 176 177 public boolean containsVertex( FlowElement flowElement ) 178 { 179 return graph.containsVertex( flowElement ); 180 } 181 182 public Set<Scope> edgeSet() 183 { 184 return graph.edgeSet(); 185 } 186 187 public Set<Scope> edgesOf( FlowElement vertex ) 188 { 189 return graph.edgesOf( vertex ); 190 } 191 192 public int inDegreeOf( FlowElement vertex ) 193 { 194 return graph.inDegreeOf( vertex ); 195 } 196 197 public Set<Scope> incomingEdgesOf( FlowElement vertex ) 198 { 199 return graph.incomingEdgesOf( vertex ); 200 } 201 202 public int outDegreeOf( FlowElement vertex ) 203 { 204 return graph.outDegreeOf( vertex ); 205 } 206 207 public Set<Scope> outgoingEdgesOf( FlowElement vertex ) 208 { 209 return graph.outgoingEdgesOf( vertex ); 210 } 211 212 public Scope removeEdge( FlowElement sourceVertex, FlowElement targetVertex ) 213 { 214 return graph.removeEdge( sourceVertex, targetVertex ); 215 } 216 217 public boolean removeEdge( Scope scope ) 218 { 219 return graph.removeEdge( scope ); 220 } 221 222 public boolean removeVertex( FlowElement flowElement ) 223 { 224 return graph.removeVertex( flowElement ); 225 } 226 227 public Set<FlowElement> vertexSet() 228 { 229 return graph.vertexSet(); 230 } 231 232 @Override 233 public Set<FlowElement> vertexSetCopy() 234 { 235 Set<FlowElement> result = Collections.newSetFromMap( new IdentityHashMap<FlowElement, Boolean>() ); 236 237 result.addAll( vertexSet() ); 238 239 return result; 240 } 241 242 @Override 243 public List<FlowElement> predecessorListOf( FlowElement flowElement ) 244 { 245 return Graphs.predecessorListOf( graph, flowElement ); 246 } 247 248 @Override 249 public List<FlowElement> successorListOf( FlowElement flowElement ) 250 { 251 return Graphs.successorListOf( graph, flowElement ); 252 } 253 254 @Override 255 public ElementGraph bindExtents() 256 { 257 Set<FlowElement> vertexSet = vertexSetCopy(); 258 259 for( FlowElement flowElement : vertexSet ) 260 { 261 if( inDegreeOf( flowElement ) == 0 ) 262 addHeadVertex( flowElement ); 263 264 if( outDegreeOf( flowElement ) == 0 ) 265 addTailVertex( flowElement ); 266 } 267 268 // be sure to test underlying container 269 if( !vertexSet().contains( Extent.head ) ) 270 throw new IllegalStateException( "did not bind head vertex to graph" ); 271 272 if( !vertexSet().contains( Extent.tail ) ) 273 throw new IllegalStateException( "did not bind tail vertex to graph" ); 274 275 return this; 276 } 277 278 @Override 279 public void writeDOT( String filename ) 280 { 281 boolean success = ElementGraphs.printElementGraph( filename, this, null ); 282 283 if( success ) 284 Util.writePDF( filename ); 285 } 286 287 @Override 288 public boolean equals( Object object ) 289 { 290 return ElementGraphs.equals( this, (ElementGraph) object ); 291 } 292 293 @Override 294 public int hashCode() 295 { 296 int result = graph.hashCode(); 297 result = 31 * result; // parity with AnnotatedGraph types 298 return result; 299 } 300 }