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  }