15
15
16
16
import com .ibm .cldk .entities .AbstractGraphEdge ;
17
17
import com .ibm .cldk .entities .CallEdge ;
18
- import com .ibm .cldk .entities .Callable ;
18
+ import com .ibm .cldk .entities .CallableVertex ;
19
19
import com .ibm .cldk .entities .SystemDepEdge ;
20
20
import com .ibm .cldk .utils .AnalysisUtils ;
21
21
import com .ibm .cldk .utils .Log ;
40
40
import com .ibm .wala .util .graph .Graph ;
41
41
import com .ibm .wala .util .graph .GraphSlicer ;
42
42
import com .ibm .wala .util .graph .traverse .DFS ;
43
+ import lombok .Data ;
44
+ import lombok .EqualsAndHashCode ;
43
45
import org .apache .commons .io .output .NullOutputStream ;
44
- import org .apache .commons .lang3 .tuple .Pair ;
45
46
import org .jgrapht .graph .DefaultDirectedGraph ;
46
47
import org .jgrapht .nio .json .JSONExporter ;
47
48
48
49
import java .io .IOException ;
49
50
import java .io .PrintStream ;
50
- import java .io .StringWriter ;
51
51
import java .util .*;
52
52
import java .util .function .BiFunction ;
53
53
import 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
+ }
57
97
58
98
/**
59
99
* The type Sdg 2 json.
@@ -66,19 +106,10 @@ public class SystemDependencyGraph {
66
106
* @return the graph exporter
67
107
*/
68
108
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 <>();
81
111
exporter .setEdgeAttributeProvider (AbstractGraphEdge ::getAttributes );
112
+ exporter .setVertexAttributeProvider (CallableVertex ::getAttributes );
82
113
return exporter ;
83
114
}
84
115
@@ -91,12 +122,12 @@ private static JSONExporter<Pair<String, Callable>, AbstractGraphEdge> getGraphE
91
122
* @param edgeLabels
92
123
* @return
93
124
*/
94
- private static org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > buildGraph (
125
+ private static org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > buildGraph (
95
126
Supplier <Iterator <Statement >> entryPoints ,
96
127
Graph <Statement > sdg , CallGraph callGraph ,
97
128
BiFunction <Statement , Statement , String > edgeLabels ) {
98
129
99
- org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > graph = new DefaultDirectedGraph <>(
130
+ org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > graph = new DefaultDirectedGraph <>(
100
131
AbstractGraphEdge .class );
101
132
102
133
// 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
131
162
&& !p .getNode ().getMethod ().equals (s .getNode ().getMethod ())) {
132
163
133
164
// 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 ()));
137
166
// 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 );
145
177
if (cgEdge == null || !cgEdge .equals (graphEdge )) {
146
178
graph .addEdge (
147
- source ,
148
- target ,
179
+ source_vertex ,
180
+ target_vertex ,
149
181
graphEdge );
150
182
} else {
151
183
graphEdge .incrementWeight ();
@@ -164,21 +196,22 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
164
196
.forEach (o -> {
165
197
166
198
// 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 );
169
201
170
202
// 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 );
175
205
206
+ if (!source .equals (target ) && target != null ) {
176
207
// 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 );
178
211
if (cgEdge instanceof CallEdge ) {
179
212
((CallEdge ) cgEdge ).incrementWeight ();
180
213
} else {
181
- graph .addEdge (source , target , new CallEdge ());
214
+ graph .addEdge (source_vertex , target_vertex , new CallEdge ());
182
215
}
183
216
}
184
217
});
@@ -193,15 +226,15 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
193
226
*
194
227
* @param input the input
195
228
* @param dependencies the dependencies
196
- * @param build The build options
229
+ * @param build The build options
197
230
* @return A List of triples containing the source, destination, and edge type
198
231
* @throws IOException the io exception
199
232
* @throws ClassHierarchyException the class hierarchy exception
200
233
* @throws IllegalArgumentException the illegal argument exception
201
234
* @throws CallGraphBuilderCancelException the call graph builder cancel
202
235
* exception
203
236
*/
204
- public static String construct (
237
+ public static List < Dependency > construct (
205
238
String input , String dependencies , String build )
206
239
throws IOException , ClassHierarchyException , IllegalArgumentException , CallGraphBuilderCancelException {
207
240
@@ -244,12 +277,7 @@ public static String construct(
244
277
+ Math .ceil ((double ) (System .currentTimeMillis () - start_time ) / 1000 ) + " seconds." );
245
278
246
279
// 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 );
253
281
254
282
// Build SDG graph
255
283
Log .info ("Building System Dependency Graph." );
@@ -267,22 +295,31 @@ public static String construct(
267
295
.getDeclaringClass ()
268
296
.getClassLoader ()
269
297
.getReference ()
270
- .equals (ClassLoaderReference .Application )));
298
+ .equals (ClassLoaderReference .Application ))
299
+ );
271
300
272
301
// A supplier to get entries
273
302
Supplier <Iterator <Statement >> sdgEntryPointsSupplier = () -> callGraph .getEntrypointNodes ().stream ()
274
303
.map (n -> (Statement ) new MethodEntryStatement (n )).iterator ();
275
304
276
- org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > sdgGraph = buildGraph (
305
+ org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > sdgGraph = buildGraph (
277
306
sdgEntryPointsSupplier ,
278
307
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
+ );
282
310
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 ());
285
322
286
- return sdgWriter . toString () ;
323
+ return edges ;
287
324
}
288
325
}
0 commit comments