1515
1616import com .ibm .cldk .entities .AbstractGraphEdge ;
1717import com .ibm .cldk .entities .CallEdge ;
18- import com .ibm .cldk .entities .Callable ;
18+ import com .ibm .cldk .entities .CallableVertex ;
1919import com .ibm .cldk .entities .SystemDepEdge ;
2020import com .ibm .cldk .utils .AnalysisUtils ;
2121import com .ibm .cldk .utils .Log ;
4040import com .ibm .wala .util .graph .Graph ;
4141import com .ibm .wala .util .graph .GraphSlicer ;
4242import com .ibm .wala .util .graph .traverse .DFS ;
43+ import lombok .Data ;
44+ import lombok .EqualsAndHashCode ;
4345import org .apache .commons .io .output .NullOutputStream ;
44- import org .apache .commons .lang3 .tuple .Pair ;
4546import org .jgrapht .graph .DefaultDirectedGraph ;
4647import org .jgrapht .nio .json .JSONExporter ;
4748
4849import java .io .IOException ;
4950import java .io .PrintStream ;
50- import java .io .StringWriter ;
5151import java .util .*;
5252import java .util .function .BiFunction ;
5353import java .util .function .Supplier ;
54-
55- import static com .ibm .cldk .CodeAnalyzer .gson ;
56- import static com .ibm .cldk .utils .AnalysisUtils .*;
54+ import java .util .stream .Collectors ;
55+
56+ import static com .ibm .cldk .utils .AnalysisUtils .createAndPutNewCallableInSymbolTable ;
57+ import static com .ibm .cldk .utils .AnalysisUtils .getCallableFromSymbolTable ;
58+
59+
60+ @ Data
61+ abstract class Dependency {
62+ public CallableVertex source ;
63+ public CallableVertex target ;
64+ }
65+
66+ @ Data
67+ @ EqualsAndHashCode (callSuper = true )
68+ class SDGDependency extends Dependency {
69+ public String sourceKind ;
70+ public String destinationKind ;
71+ public String type ;
72+ public String weight ;
73+
74+ public SDGDependency (CallableVertex source , CallableVertex target , SystemDepEdge edge ) {
75+ super .source = source ;
76+ super .target = target ;
77+ this .sourceKind = edge .getSourceKind ();
78+ this .destinationKind = edge .getDestinationKind ();
79+ this .type = edge .getType ();
80+ this .weight = String .valueOf (edge .getWeight ());
81+ }
82+ }
83+
84+ @ Data
85+ @ EqualsAndHashCode (callSuper = true )
86+ class CallDependency extends Dependency {
87+ public String type ;
88+ public String weight ;
89+
90+ public CallDependency (CallableVertex source , CallableVertex target , AbstractGraphEdge edge ) {
91+ this .source = source ;
92+ this .target = target ;
93+ this .type = edge .toString ();
94+ this .weight = String .valueOf (edge .getWeight ());
95+ }
96+ }
5797
5898/**
5999 * The type Sdg 2 json.
@@ -66,19 +106,10 @@ public class SystemDependencyGraph {
66106 * @return the graph exporter
67107 */
68108
69-
70- private static JSONExporter <Pair <String , Callable >, AbstractGraphEdge > getGraphExporter () {
71- JSONExporter <Pair <String , Callable >, AbstractGraphEdge > exporter = new JSONExporter <>(
72- pair -> {
73- Map <String , String > vertex = new HashMap <>();
74- vertex .put ("type_declaration" , pair .getLeft ());
75- vertex .put ("file_path" , pair .getRight ().getFilePath ());
76- vertex .put ("signature" , pair .getRight ().getSignature ());
77- vertex .put ("callable_declaration" , pair .getRight ().getDeclaration ());
78- return gson .toJson (vertex );
79- }
80- );
109+ private static JSONExporter <CallableVertex , AbstractGraphEdge > getGraphExporter () {
110+ JSONExporter <CallableVertex , AbstractGraphEdge > exporter = new JSONExporter <>();
81111 exporter .setEdgeAttributeProvider (AbstractGraphEdge ::getAttributes );
112+ exporter .setVertexAttributeProvider (CallableVertex ::getAttributes );
82113 return exporter ;
83114 }
84115
@@ -91,12 +122,12 @@ private static JSONExporter<Pair<String, Callable>, AbstractGraphEdge> getGraphE
91122 * @param edgeLabels
92123 * @return
93124 */
94- private static org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > buildGraph (
125+ private static org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > buildGraph (
95126 Supplier <Iterator <Statement >> entryPoints ,
96127 Graph <Statement > sdg , CallGraph callGraph ,
97128 BiFunction <Statement , Statement , String > edgeLabels ) {
98129
99- org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > graph = new DefaultDirectedGraph <>(
130+ org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > graph = new DefaultDirectedGraph <>(
100131 AbstractGraphEdge .class );
101132
102133 // We'll use forward and backward search on the DFS to identify which CFG nodes
@@ -131,21 +162,22 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
131162 && !p .getNode ().getMethod ().equals (s .getNode ().getMethod ())) {
132163
133164 // Add the source nodes to the graph as vertices
134- Pair <String , Callable > source = Optional .ofNullable (getCallableFromSymbolTable (p .getNode ().getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getNode ().getMethod ()));
135- graph .addVertex (source );
136-
165+ Map <String , String > source = Optional .ofNullable (getCallableFromSymbolTable (p .getNode ().getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getNode ().getMethod ()));
137166 // Add the target nodes to the graph as vertices
138- Pair <String , Callable > target = Optional .ofNullable (getCallableFromSymbolTable (s .getNode ().getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (s .getNode ().getMethod ()));
139- graph .addVertex (target );
140-
141- String edgeType = edgeLabels .apply (p , s );
142- SystemDepEdge graphEdge = new SystemDepEdge (p , s , edgeType );
143- SystemDepEdge cgEdge = (SystemDepEdge ) graph .getEdge (source , target );
144- if (source .getRight () != null && target .getRight () != null ) {
167+ Map <String , String > target = Optional .ofNullable (getCallableFromSymbolTable (s .getNode ().getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (s .getNode ().getMethod ()));
168+
169+ if (source != null && target != null ) {
170+ CallableVertex source_vertex = new CallableVertex (source );
171+ CallableVertex target_vertex = new CallableVertex (target );
172+ graph .addVertex (source_vertex );
173+ graph .addVertex (target_vertex );
174+ String edgeType = edgeLabels .apply (p , s );
175+ SystemDepEdge graphEdge = new SystemDepEdge (p , s , edgeType );
176+ SystemDepEdge cgEdge = (SystemDepEdge ) graph .getEdge (source_vertex , target_vertex );
145177 if (cgEdge == null || !cgEdge .equals (graphEdge )) {
146178 graph .addEdge (
147- source ,
148- target ,
179+ source_vertex ,
180+ target_vertex ,
149181 graphEdge );
150182 } else {
151183 graphEdge .incrementWeight ();
@@ -164,21 +196,22 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
164196 .forEach (o -> {
165197
166198 // Add the source nodes to the graph as vertices
167- Pair <String , Callable > source = Optional .ofNullable (getCallableFromSymbolTable (p .getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getMethod ()));
168- graph . addVertex (source );
199+ Map <String , String > source = Optional .ofNullable (getCallableFromSymbolTable (p .getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getMethod ()));
200+ CallableVertex source_vertex = new CallableVertex (source );
169201
170202 // Add the target nodes to the graph as vertices
171- Pair <String , Callable > target = Optional .ofNullable (getCallableFromSymbolTable (o .getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (o .getMethod ()));
172- graph .addVertex (target );
173-
174- if (!source .equals (target ) && source .getRight () != null && target .getRight () != null ) {
203+ Map <String , String > target = Optional .ofNullable (getCallableFromSymbolTable (o .getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (o .getMethod ()));
204+ CallableVertex target_vertex = new CallableVertex (target );
175205
206+ if (!source .equals (target ) && target != null ) {
176207 // Get the edge between the source and the target
177- AbstractGraphEdge cgEdge = graph .getEdge (source , target );
208+ graph .addVertex (source_vertex );
209+ graph .addVertex (target_vertex );
210+ AbstractGraphEdge cgEdge = graph .getEdge (source_vertex , target_vertex );
178211 if (cgEdge instanceof CallEdge ) {
179212 ((CallEdge ) cgEdge ).incrementWeight ();
180213 } else {
181- graph .addEdge (source , target , new CallEdge ());
214+ graph .addEdge (source_vertex , target_vertex , new CallEdge ());
182215 }
183216 }
184217 });
@@ -193,15 +226,15 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
193226 *
194227 * @param input the input
195228 * @param dependencies the dependencies
196- * @param build The build options
229+ * @param build The build options
197230 * @return A List of triples containing the source, destination, and edge type
198231 * @throws IOException the io exception
199232 * @throws ClassHierarchyException the class hierarchy exception
200233 * @throws IllegalArgumentException the illegal argument exception
201234 * @throws CallGraphBuilderCancelException the call graph builder cancel
202235 * exception
203236 */
204- public static String construct (
237+ public static List < Dependency > construct (
205238 String input , String dependencies , String build )
206239 throws IOException , ClassHierarchyException , IllegalArgumentException , CallGraphBuilderCancelException {
207240
@@ -244,12 +277,7 @@ public static String construct(
244277 + Math .ceil ((double ) (System .currentTimeMillis () - start_time ) / 1000 ) + " seconds." );
245278
246279 // set cyclomatic complexity for callables in the symbol table
247- callGraph .forEach (cgNode -> {
248- Callable callable = getCallableFromSymbolTable (cgNode .getMethod ()).getRight ();
249- if (callable != null ) {
250- callable .setCyclomaticComplexity (getCyclomaticComplexity (cgNode .getIR ()));
251- }
252- });
280+ AnalysisUtils .setCyclomaticComplexity (callGraph );
253281
254282 // Build SDG graph
255283 Log .info ("Building System Dependency Graph." );
@@ -267,22 +295,31 @@ public static String construct(
267295 .getDeclaringClass ()
268296 .getClassLoader ()
269297 .getReference ()
270- .equals (ClassLoaderReference .Application )));
298+ .equals (ClassLoaderReference .Application ))
299+ );
271300
272301 // A supplier to get entries
273302 Supplier <Iterator <Statement >> sdgEntryPointsSupplier = () -> callGraph .getEntrypointNodes ().stream ()
274303 .map (n -> (Statement ) new MethodEntryStatement (n )).iterator ();
275304
276- org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > sdgGraph = buildGraph (
305+ org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > sdgGraph = buildGraph (
277306 sdgEntryPointsSupplier ,
278307 prunedGraph , callGraph ,
279- (p , s ) -> String .valueOf (sdg .getEdgeLabels (p , s ).iterator ().next ()));
280-
281- JSONExporter <Pair <String , Callable >, AbstractGraphEdge > graphExporter = getGraphExporter ();
308+ (p , s ) -> String .valueOf (sdg .getEdgeLabels (p , s ).iterator ().next ())
309+ );
282310
283- StringWriter sdgWriter = new StringWriter ();
284- graphExporter .exportGraph (sdgGraph , sdgWriter );
311+ List <Dependency > edges = sdgGraph .edgeSet ().stream ()
312+ .map (abstractGraphEdge -> {
313+ CallableVertex source = sdgGraph .getEdgeSource (abstractGraphEdge );
314+ CallableVertex target = sdgGraph .getEdgeTarget (abstractGraphEdge );
315+ if (abstractGraphEdge instanceof CallEdge ) {
316+ return new CallDependency (source , target , abstractGraphEdge );
317+ } else {
318+ return new SDGDependency (source , target , (SystemDepEdge ) abstractGraphEdge );
319+ }
320+ })
321+ .collect (Collectors .toList ());
285322
286- return sdgWriter . toString () ;
323+ return edges ;
287324 }
288325}
0 commit comments