001/*
002 * Copyright (c) 2016 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.Graphs;
036import org.jgrapht.graph.SimpleDirectedGraph;
037
038/**
039 *
040 */
041public abstract class BaseElementGraph implements ElementGraph, Serializable
042  {
043  public static final ElementGraph NULL = new BaseElementGraph( new SimpleDirectedGraph<FlowElement, Scope>( Scope.class ) )
044    {
045    @Override
046    public ElementGraph copyElementGraph()
047      {
048      return null;
049      }
050    };
051
052  protected DirectedGraph<FlowElement, Scope> graph;
053
054  public BaseElementGraph()
055    {
056    }
057
058  public BaseElementGraph( DirectedGraph<FlowElement, Scope> graph )
059    {
060    this.graph = graph;
061    }
062
063  protected void copyFrom( ElementGraph elementGraph )
064    {
065    Graphs.addAllVertices( graph, elementGraph.vertexSet() );
066    Graphs.addAllEdges( graph, ElementGraphs.directed( elementGraph ), elementGraph.edgeSet() );
067    }
068
069  public boolean containsEdge( FlowElement sourceVertex, FlowElement targetVertex )
070    {
071    return graph.containsEdge( sourceVertex, targetVertex );
072    }
073
074  public boolean removeAllEdges( Collection<? extends Scope> edges )
075    {
076    return graph.removeAllEdges( edges );
077    }
078
079  public Set<Scope> removeAllEdges( FlowElement sourceVertex, FlowElement targetVertex )
080    {
081    return graph.removeAllEdges( sourceVertex, targetVertex );
082    }
083
084  public boolean removeAllVertices( Collection<? extends FlowElement> vertices )
085    {
086    return graph.removeAllVertices( vertices );
087    }
088
089  public Set<Scope> getAllEdges( FlowElement sourceVertex, FlowElement targetVertex )
090    {
091    return graph.getAllEdges( sourceVertex, targetVertex );
092    }
093
094  public Scope getEdge( FlowElement sourceVertex, FlowElement targetVertex )
095    {
096    return graph.getEdge( sourceVertex, targetVertex );
097    }
098
099  public Scope addEdge( FlowElement sourceVertex, FlowElement targetVertex )
100    {
101//     prevent multiple edges from head or to tail
102    if( !allowMultipleExtentEdges() && ( sourceVertex == Extent.head || targetVertex == Extent.tail ) && graph.containsEdge( sourceVertex, targetVertex ) )
103      return graph.getEdge( sourceVertex, targetVertex );
104
105    return graph.addEdge( sourceVertex, targetVertex );
106    }
107
108  public boolean addEdge( FlowElement sourceVertex, FlowElement targetVertex, Scope scope )
109    {
110    // prevent multiple edges from head or to tail
111    if( !allowMultipleExtentEdges() && ( sourceVertex == Extent.head || targetVertex == Extent.tail ) && graph.containsEdge( sourceVertex, targetVertex ) )
112      return true;
113
114    return graph.addEdge( sourceVertex, targetVertex, scope );
115    }
116
117  protected boolean allowMultipleExtentEdges()
118    {
119    return true;
120    }
121
122  @Override
123  public boolean addHeadVertex( FlowElement flowElement )
124    {
125    if( !graph.containsVertex( Extent.head ) )
126      graph.addVertex( Extent.head );
127
128    if( flowElement == Extent.head )
129      return false;
130
131    boolean result = true;
132
133    if( !graph.containsVertex( flowElement ) )
134      result = graph.addVertex( flowElement );
135
136    return result && graph.addEdge( Extent.head, flowElement ) != null;
137    }
138
139  @Override
140  public boolean addTailVertex( FlowElement flowElement )
141    {
142    if( !graph.containsVertex( Extent.tail ) )
143      graph.addVertex( Extent.tail );
144
145    if( flowElement == Extent.tail )
146      return false;
147
148    boolean result = true;
149
150    if( !graph.containsVertex( flowElement ) )
151      result = graph.addVertex( flowElement );
152
153    return result && graph.addEdge( flowElement, Extent.tail ) != null;
154    }
155
156  public boolean addVertex( FlowElement flowElement )
157    {
158    return graph.addVertex( flowElement );
159    }
160
161  public FlowElement getEdgeSource( Scope scope )
162    {
163    return graph.getEdgeSource( scope );
164    }
165
166  public FlowElement getEdgeTarget( Scope scope )
167    {
168    return graph.getEdgeTarget( scope );
169    }
170
171  public boolean containsEdge( Scope scope )
172    {
173    return graph.containsEdge( scope );
174    }
175
176  public boolean containsVertex( FlowElement flowElement )
177    {
178    return graph.containsVertex( flowElement );
179    }
180
181  public Set<Scope> edgeSet()
182    {
183    return graph.edgeSet();
184    }
185
186  public Set<Scope> edgesOf( FlowElement vertex )
187    {
188    return graph.edgesOf( vertex );
189    }
190
191  public int inDegreeOf( FlowElement vertex )
192    {
193    return graph.inDegreeOf( vertex );
194    }
195
196  public Set<Scope> incomingEdgesOf( FlowElement vertex )
197    {
198    return graph.incomingEdgesOf( vertex );
199    }
200
201  public int outDegreeOf( FlowElement vertex )
202    {
203    return graph.outDegreeOf( vertex );
204    }
205
206  public Set<Scope> outgoingEdgesOf( FlowElement vertex )
207    {
208    return graph.outgoingEdgesOf( vertex );
209    }
210
211  public Scope removeEdge( FlowElement sourceVertex, FlowElement targetVertex )
212    {
213    return graph.removeEdge( sourceVertex, targetVertex );
214    }
215
216  public boolean removeEdge( Scope scope )
217    {
218    return graph.removeEdge( scope );
219    }
220
221  public boolean removeVertex( FlowElement flowElement )
222    {
223    return graph.removeVertex( flowElement );
224    }
225
226  public Set<FlowElement> vertexSet()
227    {
228    return graph.vertexSet();
229    }
230
231  @Override
232  public Set<FlowElement> vertexSetCopy()
233    {
234    Set<FlowElement> result = Collections.newSetFromMap( new IdentityHashMap<FlowElement, Boolean>() );
235
236    result.addAll( vertexSet() );
237
238    return result;
239    }
240
241  @Override
242  public List<FlowElement> predecessorListOf( FlowElement flowElement )
243    {
244    return Graphs.predecessorListOf( graph, flowElement );
245    }
246
247  @Override
248  public List<FlowElement> successorListOf( FlowElement flowElement )
249    {
250    return Graphs.successorListOf( graph, flowElement );
251    }
252
253  @Override
254  public ElementGraph bindExtents()
255    {
256    Set<FlowElement> vertexSet = vertexSetCopy();
257
258    for( FlowElement flowElement : vertexSet )
259      {
260      if( inDegreeOf( flowElement ) == 0 )
261        addHeadVertex( flowElement );
262
263      if( outDegreeOf( flowElement ) == 0 )
264        addTailVertex( flowElement );
265      }
266
267    // be sure to test underlying container
268    if( !vertexSet().contains( Extent.head ) )
269      throw new IllegalStateException( "did not bind head vertex to graph" );
270
271    if( !vertexSet().contains( Extent.tail ) )
272      throw new IllegalStateException( "did not bind tail vertex to graph" );
273
274    return this;
275    }
276
277  @Override
278  public void writeDOT( String filename )
279    {
280    boolean success = ElementGraphs.printElementGraph( filename, this, null );
281
282    if( success )
283      Util.writePDF( filename );
284    }
285
286  @Override
287  public boolean equals( Object object )
288    {
289    return ElementGraphs.equals( this, (ElementGraph) object );
290    }
291
292  @Override
293  public int hashCode()
294    {
295    int result = graph.hashCode();
296    result = 31 * result; // parity with AnnotatedGraph types
297    return result;
298    }
299  }