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,18 +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 ("class_interface_declarations" , pair .getLeft ());
75
- vertex .put ("callable" , gson .toJson (pair .getRight ()));
76
- return gson .toJson (vertex );
77
- }
78
- );
79
- // exporter.setVertexAttributeProvider(v -> v.getRight().getAttributes());
109
+ private static JSONExporter <CallableVertex , AbstractGraphEdge > getGraphExporter () {
110
+ JSONExporter <CallableVertex , AbstractGraphEdge > exporter = new JSONExporter <>();
80
111
exporter .setEdgeAttributeProvider (AbstractGraphEdge ::getAttributes );
112
+ exporter .setVertexAttributeProvider (CallableVertex ::getAttributes );
81
113
return exporter ;
82
114
}
83
115
@@ -90,12 +122,12 @@ private static JSONExporter<Pair<String, Callable>, AbstractGraphEdge> getGraphE
90
122
* @param edgeLabels
91
123
* @return
92
124
*/
93
- private static org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > buildGraph (
125
+ private static org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > buildGraph (
94
126
Supplier <Iterator <Statement >> entryPoints ,
95
127
Graph <Statement > sdg , CallGraph callGraph ,
96
128
BiFunction <Statement , Statement , String > edgeLabels ) {
97
129
98
- org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > graph = new DefaultDirectedGraph <>(
130
+ org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > graph = new DefaultDirectedGraph <>(
99
131
AbstractGraphEdge .class );
100
132
101
133
// We'll use forward and backward search on the DFS to identify which CFG nodes
@@ -130,21 +162,22 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
130
162
&& !p .getNode ().getMethod ().equals (s .getNode ().getMethod ())) {
131
163
132
164
// Add the source nodes to the graph as vertices
133
- Pair <String , Callable > source = Optional .ofNullable (getCallableFromSymbolTable (p .getNode ().getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getNode ().getMethod ()));
134
- graph .addVertex (source );
135
-
165
+ Map <String , String > source = Optional .ofNullable (getCallableFromSymbolTable (p .getNode ().getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getNode ().getMethod ()));
136
166
// Add the target nodes to the graph as vertices
137
- Pair <String , Callable > target = Optional .ofNullable (getCallableFromSymbolTable (s .getNode ().getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (s .getNode ().getMethod ()));
138
- graph .addVertex (target );
139
-
140
- String edgeType = edgeLabels .apply (p , s );
141
- SystemDepEdge graphEdge = new SystemDepEdge (p , s , edgeType );
142
- SystemDepEdge cgEdge = (SystemDepEdge ) graph .getEdge (source , target );
143
- 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 );
144
177
if (cgEdge == null || !cgEdge .equals (graphEdge )) {
145
178
graph .addEdge (
146
- source ,
147
- target ,
179
+ source_vertex ,
180
+ target_vertex ,
148
181
graphEdge );
149
182
} else {
150
183
graphEdge .incrementWeight ();
@@ -163,21 +196,22 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
163
196
.forEach (o -> {
164
197
165
198
// Add the source nodes to the graph as vertices
166
- Pair <String , Callable > source = Optional .ofNullable (getCallableFromSymbolTable (p .getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getMethod ()));
167
- graph . addVertex (source );
199
+ Map <String , String > source = Optional .ofNullable (getCallableFromSymbolTable (p .getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (p .getMethod ()));
200
+ CallableVertex source_vertex = new CallableVertex (source );
168
201
169
202
// Add the target nodes to the graph as vertices
170
- Pair <String , Callable > target = Optional .ofNullable (getCallableFromSymbolTable (o .getMethod ())).orElseGet (() -> createAndPutNewCallableInSymbolTable (o .getMethod ()));
171
- graph .addVertex (target );
172
-
173
- 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 );
174
205
206
+ if (!source .equals (target ) && target != null ) {
175
207
// Get the edge between the source and the target
176
- 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 );
177
211
if (cgEdge instanceof CallEdge ) {
178
212
((CallEdge ) cgEdge ).incrementWeight ();
179
213
} else {
180
- graph .addEdge (source , target , new CallEdge ());
214
+ graph .addEdge (source_vertex , target_vertex , new CallEdge ());
181
215
}
182
216
}
183
217
});
@@ -192,15 +226,15 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
192
226
*
193
227
* @param input the input
194
228
* @param dependencies the dependencies
195
- * @param build The build options
229
+ * @param build The build options
196
230
* @return A List of triples containing the source, destination, and edge type
197
231
* @throws IOException the io exception
198
232
* @throws ClassHierarchyException the class hierarchy exception
199
233
* @throws IllegalArgumentException the illegal argument exception
200
234
* @throws CallGraphBuilderCancelException the call graph builder cancel
201
235
* exception
202
236
*/
203
- public static String construct (
237
+ public static List < Dependency > construct (
204
238
String input , String dependencies , String build )
205
239
throws IOException , ClassHierarchyException , IllegalArgumentException , CallGraphBuilderCancelException {
206
240
@@ -243,12 +277,7 @@ public static String construct(
243
277
+ Math .ceil ((double ) (System .currentTimeMillis () - start_time ) / 1000 ) + " seconds." );
244
278
245
279
// set cyclomatic complexity for callables in the symbol table
246
- callGraph .forEach (cgNode -> {
247
- Callable callable = getCallableFromSymbolTable (cgNode .getMethod ()).getRight ();
248
- if (callable != null ) {
249
- callable .setCyclomaticComplexity (getCyclomaticComplexity (cgNode .getIR ()));
250
- }
251
- });
280
+ AnalysisUtils .setCyclomaticComplexity (callGraph );
252
281
253
282
// Build SDG graph
254
283
Log .info ("Building System Dependency Graph." );
@@ -266,22 +295,31 @@ public static String construct(
266
295
.getDeclaringClass ()
267
296
.getClassLoader ()
268
297
.getReference ()
269
- .equals (ClassLoaderReference .Application )));
298
+ .equals (ClassLoaderReference .Application ))
299
+ );
270
300
271
301
// A supplier to get entries
272
302
Supplier <Iterator <Statement >> sdgEntryPointsSupplier = () -> callGraph .getEntrypointNodes ().stream ()
273
303
.map (n -> (Statement ) new MethodEntryStatement (n )).iterator ();
274
304
275
- org .jgrapht .Graph <Pair < String , Callable > , AbstractGraphEdge > sdgGraph = buildGraph (
305
+ org .jgrapht .Graph <CallableVertex , AbstractGraphEdge > sdgGraph = buildGraph (
276
306
sdgEntryPointsSupplier ,
277
307
prunedGraph , callGraph ,
278
- (p , s ) -> String .valueOf (sdg .getEdgeLabels (p , s ).iterator ().next ()));
279
-
280
- JSONExporter <Pair <String , Callable >, AbstractGraphEdge > graphExporter = getGraphExporter ();
308
+ (p , s ) -> String .valueOf (sdg .getEdgeLabels (p , s ).iterator ().next ())
309
+ );
281
310
282
- StringWriter sdgWriter = new StringWriter ();
283
- 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 ());
284
322
285
- return sdgWriter . toString () ;
323
+ return edges ;
286
324
}
287
325
}
0 commit comments