001package gudusoft.gsqlparser.dlineage.graph;
002
003import gudusoft.gsqlparser.dlineage.dataflow.model.RelationshipType;
004import gudusoft.gsqlparser.dlineage.dataflow.model.xml.*;
005import gudusoft.gsqlparser.dlineage.graph.utils.StringEscapeUtils;
006import gudusoft.gsqlparser.dlineage.util.Pair3;
007import gudusoft.gsqlparser.util.SQLUtil;
008import java.io.IOException;
009import java.util.*;
010import java.util.Map.Entry;
011import java.util.stream.Collectors;
012
013public class DataFlowGraph {
014
015    public Pair3<String, Boolean, Set<String>> generateDataFlowGraph(dataflow dataflow,
016                                                                     boolean showLinkOnly, boolean hideColumn, List<RelationshipType> relationshipTypes,
017                                                                     Map<String, String> tooltipMap) throws IOException {
018        return generateDataFlowGraph(dataflow, showLinkOnly, hideColumn, relationshipTypes, tooltipMap, false);
019    }
020
021    /**
022     * @param includeIsolatedNodes keep the tables and resultsets that take part in no relationship (a table a
023     *                             CREATE TABLE declares that nothing reads, the resultset of SELECT 1); the
024     *                             overload without it drops them from every graph but the ER graph (Mantis 4812).
025     *                             Use it with {@code showLinkOnly = false}, which keeps unlinked nodes too.
026     */
027    public Pair3<String, Boolean, Set<String>> generateDataFlowGraph(dataflow dataflow,
028                                                                     boolean showLinkOnly, boolean hideColumn, List<RelationshipType> relationshipTypes,
029                                                                     Map<String, String> tooltipMap, boolean includeIsolatedNodes) throws IOException {
030        return convertMetaInfoToGraphXML(dataflow,
031                showLinkOnly, hideColumn,
032                relationshipTypes,
033                tooltipMap, includeIsolatedNodes);
034    }
035
036    private List<Object> nodes = new ArrayList<>();
037
038    private Set<relationship> linkRelations = new HashSet<relationship>();
039
040    private List<Object> linkIds = new ArrayList<Object>();
041
042    public List<Object> getNodes() {
043        return nodes;
044    }
045
046    public List<relationship> getRelationships() {
047        return new ArrayList<relationship>(linkRelations);
048    }
049
050    private Pair3<String, Boolean, Set<String>> convertMetaInfoToGraphXML(dataflow dataflow,
051                                                                          boolean showLinkOnly, boolean hideColumn, List<RelationshipType> relationshipTypes,
052                                                                          Map<String, String> tooltipMap, boolean includeIsolatedNodes) throws IOException {
053        nodes.clear();
054        linkIds.clear();
055        linkRelations.clear();
056
057        boolean containGroup = false;
058        String columnContent = SQLUtil.getInputStreamContent(DataFlowGraph.class.getResourceAsStream("/gudusoft/gsqlparser/graph/column.template"),
059                false);
060        String tableContent = SQLUtil.getInputStreamContent(DataFlowGraph.class.getResourceAsStream("/gudusoft/gsqlparser/graph/table.template"),
061                false);
062        String linkContent = SQLUtil.getInputStreamContent(DataFlowGraph.class.getResourceAsStream("/gudusoft/gsqlparser/graph/link.template"),
063                false);
064        String graphContent = SQLUtil.getInputStreamContent(DataFlowGraph.class.getResourceAsStream("/gudusoft/gsqlparser/graph/graph.template"),
065                false);
066
067        StringBuffer tableFullBuffer = new StringBuffer();
068
069        List<table> tables = new ArrayList<table>();
070        if (dataflow.getTables() != null)
071            tables.addAll(dataflow.getTables());
072
073        if(!relationshipTypes.contains(RelationshipType.er)){
074            if (dataflow.getViews() != null)
075                tables.addAll(dataflow.getViews());
076            if (dataflow.getStages() != null)
077                tables.addAll(dataflow.getStages());
078            if (dataflow.getSequences() != null)
079                tables.addAll(dataflow.getSequences());
080            if (dataflow.getDatasources() != null)
081                tables.addAll(dataflow.getDatasources());
082            if (dataflow.getDatabases() != null)
083                tables.addAll(dataflow.getDatabases());
084            if (dataflow.getSchemas() != null)
085                tables.addAll(dataflow.getSchemas());
086            if (dataflow.getStreams() != null)
087                tables.addAll(dataflow.getStreams());
088            if (dataflow.getPaths() != null)
089                tables.addAll(dataflow.getPaths());
090            if (dataflow.getVariables() != null)
091                tables.addAll(dataflow.getVariables());
092            if (dataflow.getResultsets() != null)
093                tables.addAll(dataflow.getResultsets());
094        }
095        Map<String, table> tableMap = new HashMap<>();
096        for (table table: tables) {
097            tableMap.put(table.getId(), table);
098        }
099
100        Set<String> relationshipTableIds = new HashSet<>();
101        for (relationship relation : dataflow.getRelationships()) {
102            if( "call".equals(relation.getType())) {
103                relationshipTableIds.add(relation.getCaller().getId());
104                if(relation.getCallees()!=null){
105                    for (sourceColumn sourceColumn: relation.getCallees()){
106                        relationshipTableIds.add(sourceColumn.getId());
107                    }
108                }
109                continue;
110            }
111            if (relation.getTarget().getParent_id() != null) {
112                relationshipTableIds.add(relation.getTarget().getParent_id());
113            } else {
114                relationshipTableIds.add(relation.getTarget().getId());
115            }
116
117            if (relation.getSources() != null) {
118                for (sourceColumn sourceColumn : relation.getSources()) {
119                    if (sourceColumn.getParent_id() != null) {
120                        relationshipTableIds.add(sourceColumn.getParent_id());
121                    } else {
122                        relationshipTableIds.add(sourceColumn.getId());
123                    }
124                }
125            }
126        }
127        Iterator<String> tableIter = tableMap.keySet().iterator();
128        if(relationshipTypes.contains(RelationshipType.er)){
129//            while(tableIter.hasNext()){
130//                String tableId = tableIter.next();
131//                if(!relationshipTableIds.contains(tableId)){
132//                    table tb = tableMap.get(tableId);
133//                    if((!SQLUtil.isEmpty(tableName) && !tableName.equalsIgnoreCase(tb.getName())) ||
134//                            (!SQLUtil.isEmpty(databaseName) && !databaseName.equalsIgnoreCase(tb.getDatabase())) ||
135//                            (!SQLUtil.isEmpty(schemaName) && !schemaName.equalsIgnoreCase(tb.getSchema())) ||
136//                            (!SQLUtil.isEmpty(serverName) && !serverName.equalsIgnoreCase(tb.getServer()))){
137//                        tableIter.remove();
138//                    }
139//                }
140//            }
141        }
142        else if (!includeIsolatedNodes) {
143            while(tableIter.hasNext()){
144                if(!relationshipTableIds.contains(tableIter.next())){
145                    tableIter.remove();
146                }
147            }
148        }
149        Map<String, Map<String, List<column>>> tableColumns = new HashMap<String, Map<String, List<column>>>();
150        Set<String> columnSet = new HashSet<String>();
151        Set<String> linkColumnSet = new HashSet<String>();
152
153        boolean showCallRelation = relationshipTypes.contains(RelationshipType.call);
154
155        Map<String, procedure> procedureMap = new HashMap<>();
156        if (relationshipTypes.contains(RelationshipType.call)) {
157            List<procedure> procedures = new ArrayList<>(dataflow.getProcedures());
158            if (dataflow.getPackages() != null) {
159                for (oraclePackage pkg : dataflow.getPackages()) {
160                    procedures.addAll(pkg.getProcedures());
161                }
162            }
163            procedureMap = procedures.stream().collect(Collectors.toMap(
164                    t -> t.getId(),
165                    t -> t,
166                    (existingValue, newValue) -> newValue
167            ));
168
169
170            Iterator<String> procedureIter = procedureMap.keySet().iterator();
171
172            while (procedureIter.hasNext()) {
173                if (!relationshipTableIds.contains(procedureIter.next())) {
174                    procedureIter.remove();
175                }
176            }
177
178            procedureIter = procedureMap.keySet().iterator();
179
180            while (procedureIter.hasNext()) {
181                procedure procedure = procedureMap.get(procedureIter.next());
182                String tableId = "table-" + procedure.getId();
183                nodes.add(procedure);
184                String content = new String(tableContent);
185                content = content.replace("{tableId}", "table-" + procedure.getId());
186
187                String tableLabel = procedure.getName();
188                if (tableLabel.length() > 25) {
189                    String shortLabel = getShortLabel(tableLabel, 25);
190                    if (tooltipMap != null) {
191                        tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
192                    }
193                    tableLabel = shortLabel;
194
195                }
196
197                content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
198
199                StringBuffer columnBuffer = new StringBuffer();
200                String columnId = "column-" + procedure.getId();
201                columnSet.add(columnId);
202                String content1 = new String(columnContent);
203                content1 = content1.replace("{columnId}", columnId);
204                content1 = content1.replace("{columnPosY}", "0");
205                content1 = content1.replace("{columnLabel}", getProcedureType(procedure));
206//                              content1 = content1.replace("height=\"16\"", "height=\"0\"");
207                columnBuffer.append(content1).append("\n");
208
209                content = content.replace("{columns}", columnBuffer.toString());
210                {
211                    content = content.replace("{contentColor}", "#9999ff");
212                    content = content.replace("{labelColor}", "#DBDADA");
213                }
214                tableFullBuffer.append(content).append("\n");
215            }
216
217
218            Iterator<String> dbObjIter = tableMap.keySet().iterator();
219            while (dbObjIter.hasNext()) {
220                table table = tableMap.get(dbObjIter.next());
221                String tableId = "table-" + table.getId();
222                nodes.add(table);
223                String content = new String(tableContent);
224                content = content.replace("{tableId}", "table-" + table.getId());
225
226                String tableLabel = table.getName();
227                if (tableLabel.length() > 25) {
228                    String shortLabel = getShortLabel(tableLabel, 25);
229                    if (tooltipMap != null) {
230                        tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
231                    }
232                    tableLabel = shortLabel;
233
234                }
235
236                content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
237
238                StringBuffer columnBuffer = new StringBuffer();
239                String columnId = "column-" + table.getId();
240                columnSet.add(columnId);
241                String content1 = new String(columnContent);
242                content1 = content1.replace("{columnId}", columnId);
243                content1 = content1.replace("{columnPosY}", "0");
244                content1 = content1.replace("{columnLabel}", table.getType());
245//                              content1 = content1.replace("height=\"16\"", "height=\"0\"");
246                columnBuffer.append(content1).append("\n");
247
248                content = content.replace("{columns}", columnBuffer.toString());
249                {
250                    content = content.replace("{contentColor}", "#9999ff");
251                    content = content.replace("{labelColor}", "#DBDADA");
252                }
253                tableFullBuffer.append(content).append("\n");
254            }
255        }
256
257        Map<String, process> processMap = new HashMap<>();
258        for (process process : dataflow.getProcesses()) {
259            processMap.put(process.getId(), process);
260        }
261        if(dataflow.getProcesses()!=null){
262            Iterator<String> processIter = processMap.keySet().iterator();
263            while (processIter.hasNext()) {
264                if (!relationshipTableIds.contains(processIter.next())) {
265                    processIter.remove();
266                }
267            }
268
269            processIter = processMap.keySet().iterator();
270            while (processIter.hasNext()) {
271                process process = processMap.get(processIter.next());
272                String tableId = "table-"+process.getId();
273                columnSet.add(tableId);
274                nodes.add(process);
275                String content = new String(tableContent);
276                content = content.replace("{tableId}", "table-" + process.getId());
277
278                String tableLabel = process.getName();
279                if (tableLabel.length() > 25) {
280                    String shortLabel = getShortLabel(tableLabel, 25);
281                    if (tooltipMap != null) {
282                        tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
283                    }
284                    tableLabel = shortLabel;
285
286                }
287
288                content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
289
290                StringBuffer columnBuffer = new StringBuffer();
291                String columnId = "column-" + process.getId();
292                String content1 = new String(columnContent);
293                content1 = content1.replace("{columnId}", columnId);
294                content1 = content1.replace("{columnPosY}", "0");
295                content1 = content1.replace("{columnLabel}", "hide-table-column");
296                content1 = content1.replace("height=\"16\"", "height=\"0\"");
297                columnBuffer.append(content1).append("\n");
298
299
300                content = content.replace("{columns}", columnBuffer.toString());
301                {
302                    content = content.replace("{contentColor}", "#9999ff");
303                    content = content.replace("{labelColor}", "#DBDADA");
304                }
305                tableFullBuffer.append(content).append("\n");
306            }
307        }
308        tableIter = tableMap.keySet().iterator();
309        while (tableIter.hasNext()) {
310            table currentTable = tableMap.get(tableIter.next());
311//            if (currentTable.getColumns() == null
312//                    || currentTable.getColumns().isEmpty())
313//                continue;
314            if(showCallRelation){
315                continue;
316            }
317            nodes.add(currentTable);
318            String tableId = "table-"+currentTable.getId();
319            columnSet.add(tableId);
320
321            StringBuffer columnBuffer = new StringBuffer();
322
323            if (currentTable.isTable() || currentTable.isView() || currentTable.isCursor() || currentTable.isDatabaseType() || currentTable.isSchemaType() || currentTable.isStage() || currentTable.isSequence() || currentTable.isDataSource() || currentTable.isStream() || currentTable.isFile()|| currentTable.isVariable()) {
324                Map<String, List<column>> columnMap = new LinkedHashMap<String, List<column>>();
325                tableColumns.put(currentTable.getId(), columnMap);
326                for (int k = 0; k < currentTable.getColumns().size(); k++) {
327                    column column = currentTable.getColumns().get(k);
328                    String columnLabel = column.getName();
329                    //add by grq 2023.01.10 issue=I69NOU
330                    if(relationshipTypes.contains(RelationshipType.er)){
331                        if(column.standsForStar() || columnLabel.equalsIgnoreCase("relationRows")){
332                            continue;
333                        }
334                    }
335                    //end by grq
336                    List<column> columns;
337                    if (!columnMap.containsKey(columnLabel)) {
338                        columns = new ArrayList<column>();
339                        columnMap.put(columnLabel, columns);
340                    } else {
341                        columns = columnMap.get(columnLabel);
342                    }
343                    columns.add(column);
344                }
345
346                Iterator<Entry<String, List<column>>> iterator = columnMap
347                        .entrySet().iterator();
348                for (int k = 0; k < columnMap.size(); k++) {
349                    Entry<String, List<column>> entry = iterator.next();
350                    nodes.add(entry.getValue());
351                    String content = columnContent;
352
353                    String columnId = "column-"
354                            + currentTable.getId()
355                            + "-index-"
356                            + k;
357                    if(columnSet.contains(columnId)){
358                        continue;
359                    }
360                    columnSet.add(columnId);
361
362                    content = content.replace("{columnId}", columnId);
363                    content = content.replace("{columnPosY}",
364                            String.valueOf(35 * k));
365                    String columnLabel = entry.getKey();
366                    if (columnLabel.length() > 25) {
367                        String shortLabel = getShortLabel(columnLabel, 25);
368                        if (tooltipMap != null) {
369                            tooltipMap.put(shortLabel.replace("\r\n", "\n")
370                                    .replace("\n", " "), columnLabel);
371                        }
372                        columnLabel = shortLabel;
373
374                    }
375                    content = content.replace("{columnLabel}",
376                            StringEscapeUtils.escapeXml(columnLabel));
377                    columnBuffer.append(content).append("\n");
378                }
379            } else {
380                for (int k = 0; k < currentTable.getColumns().size(); k++) {
381                    column column = currentTable.getColumns().get(k);
382                    nodes.add(column);
383                    String content = new String(columnContent);
384
385                    String columnParentId = currentTable.getId();
386                    String columnId = column.getId();
387                    columnId = convertColumnId(tableColumns,
388                            columnId,
389                            columnParentId);
390
391                    columnId = "column-" + columnId;
392                    if(columnSet.contains(columnId)){
393                        continue;
394                    }
395                    columnSet.add(columnId);
396
397                    content = content.replace("{columnId}", columnId);
398                    content = content.replace("{columnPosY}",
399                            String.valueOf(35 * k));
400                    String columnLabel = column.getName();
401                    if (columnLabel.length() > 25) {
402                        String shortLabel = getShortLabel(columnLabel, 25);
403                        if (tooltipMap != null) {
404                            tooltipMap.put(shortLabel.replace("\r\n", "\n")
405                                    .replace("\n", " "), columnLabel);
406                        }
407                        columnLabel = shortLabel;
408
409                    }
410                    content = content.replace("{columnLabel}",
411                            StringEscapeUtils.escapeXml(columnLabel));
412                    columnBuffer.append(content).append("\n");
413                }
414            }
415            String content = new String(tableContent);
416            content = content.replace("{tableId}",
417                    "table-" + currentTable.getId());
418
419            String tableLabel = currentTable.getName();
420            if (tableLabel.length() > 25) {
421                String shortLabel = getShortLabel(tableLabel, 25);
422                if (tooltipMap != null) {
423                    tooltipMap.put(shortLabel.replace("\r\n", "\n")
424                                    .replace("\n", " "),
425                            tableLabel);
426                }
427                tableLabel = shortLabel;
428
429            }
430
431            if(columnBuffer.length() == 0){
432                String columnId = "column-" + currentTable.getId();
433                String content1 = new String(columnContent);
434                content1 = content1.replace("{columnId}", columnId);
435                content1 = content1.replace("{columnPosY}", "0");
436                content1 = content1.replace("{columnLabel}", "hide-table-column");
437                content1 = content1.replace("height=\"16\"", "height=\"0\"");
438                columnBuffer.append(content1).append("\n");
439            }
440
441            content = content.replace("{tableLabel}",
442                    StringEscapeUtils.escapeXml(tableLabel));
443
444            String columnString = columnBuffer.toString();
445            if (hideColumn) {
446                columnString = columnString.replace("height=\"16\"", "height=\"0\"");
447            }
448            content = content.replace("{columns}", columnString);
449            if (currentTable.isView()) {
450                content = content.replace("{contentColor}", "#ff99cc");
451                content = content.replace("{labelColor}", "#ffccff");
452            } else if (currentTable.isStage()) {
453                content = content.replace("{contentColor}", "#87CEFA");
454                content = content.replace("{labelColor}", "#87CEFA");
455            } else if (currentTable.isSequence()) {
456                content = content.replace("{contentColor}", "#87CEFA");
457                content = content.replace("{labelColor}", "#87CEFA");
458            } else if (currentTable.isDataSource()) {
459                content = content.replace("{contentColor}", "#87CEFA");
460                content = content.replace("{labelColor}", "#87CEFA");
461            } else if (currentTable.isDatabaseType()) {
462                content = content.replace("{contentColor}", "#87CEFA");
463                content = content.replace("{labelColor}", "#87CEFA");
464            } else if (currentTable.isSchemaType()) {
465                content = content.replace("{contentColor}", "#87CEFA");
466                content = content.replace("{labelColor}", "#87CEFA");
467            } else if (currentTable.isStream()) {
468                content = content.replace("{contentColor}", "#87CEFA");
469                content = content.replace("{labelColor}", "#87CEFA");
470            } else if (currentTable.isFile()) {
471                content = content.replace("{contentColor}", "#87CEFA");
472                content = content.replace("{labelColor}", "#87CEFA");
473            } else if (currentTable.isCursor()) {
474                content = content.replace("{contentColor}", "#87CEFA");
475                content = content.replace("{labelColor}", "#87CEFA");
476            } else if (currentTable.isVariable()) {
477                content = content.replace("{contentColor}", "#87CEFA");
478                content = content.replace("{labelColor}", "#87CEFA");
479            } else if (currentTable.isResultSet()) {
480                content = content.replace("{contentColor}", "#009944");
481                content = content.replace("{labelColor}", "#aaffcc");
482            } else {
483                content = content.replace("{contentColor}", "#9999ff");
484                content = content.replace("{labelColor}", "#DBDADA");
485            }
486            tableFullBuffer.append(content).append("\n");
487
488            containGroup = true;
489        }
490
491        StringBuffer linkBuffer = new StringBuffer();
492        List<relationship> relationships = dataflow.getRelationships();
493        if (relationshipTypes.contains(RelationshipType.join)) {
494            relationships = relationships.stream().filter(t -> t.getType().equals("join") || t.getType().equals("fdd"))
495                    .collect(Collectors.toList());
496        }
497        else if (relationshipTypes.contains(RelationshipType.call)) {
498            relationships = relationships.stream().filter(t -> t.getType().equals("call"))
499                    .collect(Collectors.toList());
500        }
501
502        if (relationships != null) {
503            List<String> links = new ArrayList<String>();
504            for (int i = 0; i < relationships.size(); i++) {
505                relationship relationship = relationships.get(i);
506
507                if (relationship.getTarget() == null || relationship.getSources() == null || relationship.getSources().isEmpty())
508                    continue;
509                if (!relationshipTypes.contains(RelationshipType.valueOf(relationship.getType()))) {
510                    if (relationshipTypes.contains(RelationshipType.join)
511                            && relationship.getType()
512                            .equals(RelationshipType.fdd.name())) {
513                        if (!traceJoin(relationship, relationships, tableColumns, 0)) {
514                            continue;
515                        }
516                    } else {
517                        continue;
518                    }
519                }
520
521                if (RelationshipType.call.equals(RelationshipType.valueOf(relationship.getType()))) {
522                    targetColumn target = relationship.getCaller();
523                    String targetColumnId = target.getId();
524                    if (relationship.getCallees() != null) {
525                        List<sourceColumn> linkTables = relationship.getCallees();
526                        for (int k = 0; k < linkTables.size(); k++) {
527                            sourceColumn source = linkTables.get(k);
528                            String sourceColumnId = source.getId();
529                            String content = linkContent;
530                            String sourceId = "column-" + sourceColumnId;
531//                                                      if (sourceColumnId != null && sourceColumnId.indexOf("-") == -1) {
532//                                                              sourceId = "table-" + sourceColumnId;
533//                                                      }
534                            String targetId = "column-" + targetColumnId;
535//                                                      if (targetColumnId != null && targetColumnId.indexOf("-") == -1) {
536//                                                              targetId = "table-" + targetColumnId;
537//                                                      }
538
539                            //call relation的箭头方向和fdd是相反的
540                            content = content.replace("{sourceId}", targetId);
541                            content = content.replace("{targetId}", sourceId);
542
543                            if (columnSet.contains(sourceId) && columnSet.contains(targetId)) {
544                                String temp = content;
545                                if (!links.contains(temp)) {
546                                    links.add(temp);
547
548                                    linkColumnSet.add(sourceId);
549                                    linkColumnSet.add(targetId);
550
551                                    String linkId = "link_" + relationship.getId() + "_" + sourceColumnId + "_"
552                                            + targetColumnId;
553                                    content = content.replace("{linkId}", linkId);
554                                    linkIds.add(linkId);
555                                    linkRelations.add(relationship);
556                                    linkBuffer.append(content).append("\n");
557                                }
558                            } else {
559                                System.err.println("Can't get " + "link_" + relationship.getId() + "_" + sourceColumnId + "_"
560                                        + targetColumnId);
561                            }
562                        }
563                    }
564                } else {
565                    targetColumn target = relationship.getTarget();
566                    String targetColumnId = target.getId();
567                    String targetParentId = target.getParent_id();
568
569                    targetColumnId = convertColumnId(tableColumns,
570                            targetColumnId,
571                            targetParentId);
572                    if (targetParentId == null) {
573                        targetColumnId = target.getTarget_id();
574                    }
575
576                    if (relationship.getSources() != null) {
577                        List<sourceColumn> linkTables = relationship.getSources();
578                        for (int k = 0; k < linkTables.size(); k++) {
579                            sourceColumn source = linkTables.get(k);
580
581                            String sourceColumnId = source.getId();
582                            String sourceParentId = source.getParent_id();
583                            sourceColumnId = convertColumnId(tableColumns,
584                                    sourceColumnId,
585                                    sourceParentId);
586                            if (sourceParentId == null) {
587                                sourceColumnId = source.getSource_id();
588                            }
589
590                            String content = linkContent;
591
592                            if (relationship.getType()
593                                    .equals(RelationshipType.join.name())) {
594                                content = content.replace("type=\"line\"",
595                                        "type=\"dashed\"");
596                            }
597
598                            String sourceId = "column-" + sourceColumnId;
599                            if (sourceColumnId != null && sourceColumnId.indexOf("-") == -1) {
600                                sourceId = "table-" + sourceColumnId;
601                            }
602                            String targetId = "column-" + targetColumnId;
603                            if (targetColumnId != null && targetColumnId.indexOf("-") == -1) {
604                                targetId = "table-" + targetColumnId;
605                            }
606                            content = content.replace("{sourceId}", sourceId);
607                            content = content.replace("{targetId}", targetId);
608
609                            if (columnSet.contains(sourceId)
610                                    && columnSet.contains(targetId)) {
611                                String temp = content;
612                                if (!links.contains(temp)) {
613                                    links.add(temp);
614
615                                    linkColumnSet.add(sourceId);
616                                    linkColumnSet.add(targetId);
617
618                                    String linkId = "link_"
619                                            + relationship.getId()
620                                            + "_"
621                                            + sourceColumnId
622                                            + "_"
623                                            + targetColumnId;
624                                    content = content.replace("{linkId}", linkId);
625                                    linkIds.add(linkId);
626                                    linkRelations.add(relationship);
627                                    linkBuffer.append(content).append("\n");
628                                } else {
629                                    linkRelations.add(relationship);
630                                }
631                            } else {
632                                System.err.println("Can't get "
633                                        + "link_"
634                                        + relationship.getId()
635                                        + "_"
636                                        + sourceColumnId
637                                        + "_"
638                                        + targetColumnId);
639                            }
640                        }
641                    }
642                }
643            }
644        }
645
646        if (showLinkOnly) {
647            nodes.clear();
648            StringBuffer tableLinkBuffer = new StringBuffer();
649            int showColumnCount = 0;
650
651            if (relationshipTypes.contains(RelationshipType.call)) {
652                Iterator<String> procedureIter = procedureMap.keySet().iterator();
653                while (procedureIter.hasNext()) {
654                    procedure procedure = procedureMap.get(procedureIter.next());
655                    String tableId = "table-" + procedure.getId();
656                    columnSet.add(tableId);
657                    nodes.add(procedure);
658                    String content = new String(tableContent);
659                    content = content.replace("{tableId}", "table-" + procedure.getId());
660
661                    String tableLabel = procedure.getName();
662                    if (tableLabel.length() > 25) {
663                        String shortLabel = getShortLabel(tableLabel, 25);
664                        if (tooltipMap != null) {
665                            tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
666                        }
667                        tableLabel = shortLabel;
668
669                    }
670
671                    content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
672
673                    StringBuffer columnBuffer = new StringBuffer();
674                    String columnId = "column-" + procedure.getId();
675                    String content1 = new String(columnContent);
676                    content1 = content1.replace("{columnId}", columnId);
677                    content1 = content1.replace("{columnPosY}", "0");
678                    content1 = content1.replace("{columnLabel}", getProcedureType(procedure));
679//                                      content1 = content1.replace("height=\"16\"", "height=\"0\"");
680                    columnBuffer.append(content1).append("\n");
681
682                    content = content.replace("{columns}", columnBuffer.toString());
683                    {
684                        content = content.replace("{contentColor}", "#9999ff");
685                        content = content.replace("{labelColor}", "#DBDADA");
686                    }
687                    tableFullBuffer.append(content).append("\n");
688                    tableLinkBuffer.append(content).append("\n");
689                }
690
691                Iterator<String> dbObjIter = tableMap.keySet().iterator();
692                while (dbObjIter.hasNext()) {
693                    table table = tableMap.get(dbObjIter.next());
694                    String tableId = "table-" + table.getId();
695                    nodes.add(table);
696                    String content = new String(tableContent);
697                    content = content.replace("{tableId}", "table-" + table.getId());
698
699                    String tableLabel = table.getName();
700                    if (tableLabel.length() > 25) {
701                        String shortLabel = getShortLabel(tableLabel, 25);
702                        if (tooltipMap != null) {
703                            tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
704                        }
705                        tableLabel = shortLabel;
706
707                    }
708
709                    content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
710
711                    StringBuffer columnBuffer = new StringBuffer();
712                    String columnId = "column-" + table.getId();
713                    columnSet.add(columnId);
714                    String content1 = new String(columnContent);
715                    content1 = content1.replace("{columnId}", columnId);
716                    content1 = content1.replace("{columnPosY}", "0");
717                    content1 = content1.replace("{columnLabel}", table.getType());
718                    columnBuffer.append(content1).append("\n");
719
720                    content = content.replace("{columns}", columnBuffer.toString());
721                    {
722                        content = content.replace("{contentColor}", "#9999ff");
723                        content = content.replace("{labelColor}", "#DBDADA");
724                    }
725                    tableFullBuffer.append(content).append("\n");
726                    tableLinkBuffer.append(content).append("\n");
727                }
728            }
729
730            if(dataflow.getProcesses()!=null){
731                Iterator<String> processIter = processMap.keySet().iterator();
732                while (processIter.hasNext()) {
733                    process process = processMap.get(processIter.next());
734                    if(!linkColumnSet.contains("table-" + process.getId())) {
735                        continue;
736                    }
737                    nodes.add(process);
738                    String tableId = "table-"+process.getId();
739                    columnSet.add(tableId);
740                    String content = new String(tableContent);
741                    content = content.replace("{tableId}", "table-" + process.getId());
742
743                    String tableLabel = process.getName();
744                    if (tableLabel.length() > 25) {
745                        String shortLabel = getShortLabel(tableLabel, 25);
746                        if (tooltipMap != null) {
747                            tooltipMap.put(shortLabel.replace("\r\n", "\n").replace("\n", " "), tableLabel);
748                        }
749                        tableLabel = shortLabel;
750
751                    }
752
753                    content = content.replace("{tableLabel}", StringEscapeUtils.escapeXml(tableLabel));
754
755                    StringBuffer columnBuffer = new StringBuffer();
756                    String columnId = "column-" + process.getId();
757                    String content1 = new String(columnContent);
758                    content1 = content1.replace("{columnId}", columnId);
759                    content1 = content1.replace("{columnPosY}", "0");
760                    content1 = content1.replace("{columnLabel}", "hide-table-column");
761                    content1 = content1.replace("height=\"16\"", "height=\"0\"");
762                    columnBuffer.append(content1).append("\n");
763
764
765                    content = content.replace("{columns}", columnBuffer.toString());
766                    {
767                        content = content.replace("{contentColor}", "#9999ff");
768                        content = content.replace("{labelColor}", "#DBDADA");
769                    }
770                    tableFullBuffer.append(content).append("\n");
771                    tableLinkBuffer.append(content).append("\n");
772                }
773            }
774
775            tableIter = tableMap.keySet().iterator();
776            while (tableIter.hasNext()) {
777                table currentTable = tableMap.get(tableIter.next());
778                if(showCallRelation){
779                    continue;
780                }
781                if (currentTable.getColumns() == null || currentTable.getColumns().isEmpty()) {
782                    if(!linkColumnSet.contains("table-" + currentTable.getId())) {
783                        continue;
784                    }
785                }
786
787                //包含在TableLevelLineage中则不删除,不包含如无link则删除
788                boolean removeTable = !linkColumnSet.contains("table-" + currentTable.getId());
789
790                nodes.add(currentTable);
791                StringBuffer columnBuffer = new StringBuffer();
792                if (currentTable.isTable() || currentTable.isView() || currentTable.isCursor() || currentTable.isDatabaseType() || currentTable.isSchemaType() || currentTable.isStage() || currentTable.isSequence() || currentTable.isDataSource() || currentTable.isStream() || currentTable.isFile()|| currentTable.isVariable()) {
793                    Map<String, List<column>> columnMap = new LinkedHashMap<String, List<column>>();
794                    for (int k = 0; k < currentTable.getColumns().size(); k++) {
795                        column column = currentTable.getColumns().get(k);
796                        String columnLabel = column.getName();
797                        List<column> columns;
798                        if (!columnMap.containsKey(columnLabel)) {
799                            columns = new ArrayList<column>();
800                            columnMap.put(columnLabel, columns);
801                        } else {
802                            columns = columnMap.get(columnLabel);
803                        }
804                        columns.add(column);
805                    }
806
807                    Iterator<Entry<String, List<column>>> iterator = columnMap.entrySet()
808                            .iterator();
809                    for (int k = 0; k < columnMap.size(); k++) {
810                        Entry<String, List<column>> entry = iterator.next();
811                        String columnId = "column-"
812                                + currentTable.getId()
813                                + "-index-"
814                                + k;
815                        if ((currentTable.isTable() || currentTable.isView() || currentTable.isCursor() || currentTable.isDatabaseType() || currentTable.isSchemaType() || currentTable.isStage() || currentTable.isSequence() || currentTable.isDataSource() || currentTable.isStream() || currentTable.isFile()|| currentTable.isVariable())
816                                && !linkColumnSet.contains(columnId))
817                            continue;
818
819                        removeTable = false;
820                        nodes.add(entry.getValue());
821
822                        String content = new String(columnContent);
823                        content = content.replace("{columnId}", columnId);
824                        content = content.replace("{columnPosY}",
825                                String.valueOf(35 * showColumnCount));
826                        String columnLabel = entry.getKey();
827                        if (columnLabel.length() > 25) {
828                            String shortLabel = getShortLabel(columnLabel, 25);
829                            if (tooltipMap != null) {
830                                tooltipMap.put(shortLabel.replace("\r\n",
831                                                "\n").replace("\n", " "),
832                                        columnLabel);
833                            }
834                            columnLabel = shortLabel;
835
836                        }
837                        content = content.replace("{columnLabel}",
838                                StringEscapeUtils.escapeXml(columnLabel));
839                        columnBuffer.append(content).append("\n");
840                        showColumnCount++;
841                    }
842                } else {
843                    for (int k = 0; k < currentTable.getColumns().size(); k++) {
844                        column column = currentTable.getColumns().get(k);
845
846                        String columnParentId = currentTable.getId();
847                        String columnId = column.getId();
848                        columnId = convertColumnId(tableColumns,
849                                columnId,
850                                columnParentId);
851
852                        columnId = "column-" + columnId;
853                        if (!(currentTable.isTable() || currentTable.isView() || currentTable.isCursor() || currentTable.isDatabaseType() || currentTable.isSchemaType() || currentTable.isStage() || currentTable.isSequence() || currentTable.isDataSource() || currentTable.isStream() || currentTable.isFile()|| currentTable.isVariable())
854                                && !linkColumnSet.contains(columnId))
855                            continue;
856
857                        removeTable = false;
858                        nodes.add(column);
859
860                        String content = new String(columnContent);
861                        content = content.replace("{columnId}", columnId);
862                        content = content.replace("{columnPosY}",
863                                String.valueOf(35 * showColumnCount));
864                        String columnLabel = column.getName();
865                        if (columnLabel.length() > 25) {
866                            String shortLabel = getShortLabel(columnLabel, 25);
867                            if (tooltipMap != null) {
868                                tooltipMap.put(shortLabel.replace("\r\n",
869                                                "\n").replace("\n", " "),
870                                        columnLabel);
871                            }
872                            columnLabel = shortLabel;
873
874                        }
875                        content = content.replace("{columnLabel}",
876                                StringEscapeUtils.escapeXml(columnLabel));
877                        columnBuffer.append(content).append("\n");
878                        showColumnCount++;
879                    }
880                }
881
882                if (removeTable) {
883                    nodes.remove(currentTable);
884                    continue;
885                } else {
886                    if (columnBuffer.toString().trim().length() == 0) {
887                        String columnId = "column-" + currentTable.getId();
888                        String content1 = new String(columnContent);
889                        content1 = content1.replace("{columnId}", columnId);
890                        content1 = content1.replace("{columnPosY}", "0");
891                        content1 = content1.replace("{columnLabel}", "hide-table-column");
892                        content1 = content1.replace("height=\"16\"", "height=\"0\"");
893                        columnBuffer.append(content1).append("\n");
894                    }
895                }
896
897                String content = new String(tableContent);
898                content = content.replace("{tableId}",
899                        "table-" + currentTable.getId());
900
901                String tableLabel = currentTable.getName();
902                if (tableLabel.length() > 25) {
903                    String shortLabel = getShortLabel(tableLabel, 25);
904                    if (tooltipMap != null) {
905                        tooltipMap.put(shortLabel.replace("\r\n", "\n")
906                                .replace("\n", " "), tableLabel);
907                    }
908                    tableLabel = shortLabel;
909                }
910
911                content = content.replace("{tableLabel}",
912                        StringEscapeUtils.escapeXml(tableLabel));
913                String columnString = columnBuffer.toString();
914                if (hideColumn) {
915                    columnString = columnString.replace("height=\"16\"", "height=\"0\"");
916                }
917                content = content.replace("{columns}", columnString);
918
919                if (currentTable.isView()) {
920                    content = content.replace("{contentColor}", "#ff99cc");
921                    content = content.replace("{labelColor}", "#ffccff");
922                } else if (currentTable.isStage()) {
923                    content = content.replace("{contentColor}", "#87CEFA");
924                    content = content.replace("{labelColor}", "#87CEFA");
925                } else if (currentTable.isSequence()) {
926                    content = content.replace("{contentColor}", "#87CEFA");
927                    content = content.replace("{labelColor}", "#87CEFA");
928                } else if (currentTable.isDataSource()) {
929                    content = content.replace("{contentColor}", "#87CEFA");
930                    content = content.replace("{labelColor}", "#87CEFA");
931                } else if (currentTable.isDatabaseType()) {
932                    content = content.replace("{contentColor}", "#87CEFA");
933                    content = content.replace("{labelColor}", "#87CEFA");
934                } else if (currentTable.isSchemaType()) {
935                    content = content.replace("{contentColor}", "#87CEFA");
936                    content = content.replace("{labelColor}", "#87CEFA");
937                } else if (currentTable.isStream()) {
938                    content = content.replace("{contentColor}", "#87CEFA");
939                    content = content.replace("{labelColor}", "#87CEFA");
940                } else if (currentTable.isFile()) {
941                    content = content.replace("{contentColor}", "#87CEFA");
942                    content = content.replace("{labelColor}", "#87CEFA");
943                } else if (currentTable.isVariable()) {
944                    content = content.replace("{contentColor}", "#87CEFA");
945                    content = content.replace("{labelColor}", "#87CEFA");
946                } else if (currentTable.isCursor()) {
947                    content = content.replace("{contentColor}", "#87CEFA");
948                    content = content.replace("{labelColor}", "#87CEFA");
949                } else if (currentTable.isResultSet()) {
950                    content = content.replace("{contentColor}", "#009944");
951                    content = content.replace("{labelColor}", "#aaffcc");
952                } else {
953                    content = content.replace("{contentColor}", "#9999ff");
954                    content = content.replace("{labelColor}", "#DBDADA");
955                }
956                tableLinkBuffer.append(content).append("\n");
957                containGroup = true;
958            }
959
960            graphContent = graphContent.replace("{nodes}",
961                    tableLinkBuffer.toString());
962        } else {
963            graphContent = graphContent.replace("{nodes}",
964                    tableFullBuffer.toString());
965        }
966
967        nodes.addAll(linkIds);
968        graphContent = graphContent.replace("{links}", linkBuffer.toString());
969        Set<String> dbObjIds = new LinkedHashSet<>();
970        dbObjIds.addAll(tableMap.keySet());
971        dbObjIds.addAll(processMap.keySet());
972        dbObjIds.addAll(procedureMap.keySet());
973        return new Pair3<String, Boolean, Set<String>>(graphContent, containGroup, dbObjIds);
974    }
975
976    private CharSequence getProcedureType(procedure procedure) {
977        String type = procedure.getType().toLowerCase(Locale.ROOT);
978        if (type.indexOf("procedure") != -1) {
979            return "procedure";
980        } else if (type.indexOf("function") != -1) {
981            return "function";
982        } else if (type.indexOf("trigger") != -1) {
983            return "trigger";
984        } else if (type.indexOf("package") != -1) {
985            return "package";
986        } else if (type.indexOf("macro") != -1) {
987            return "macro";
988        } else {
989            return type;
990        }
991    }
992
993    private boolean traceJoin(relationship relationship, List<relationship> relationships,
994                              Map<String, Map<String, List<column>>> tableColumns, int level) {
995        targetColumn target = relationship.getTarget();
996        String targetColumnId = target.getId();
997        String targetParentId = target.getParent_id();
998
999        targetColumnId = convertColumnId(tableColumns,
1000                targetColumnId,
1001                targetParentId);
1002
1003        for (int i = 0; i < relationships.size(); i++) {
1004            relationship tempRelation = relationships.get(i);
1005
1006            if (relationship == tempRelation)
1007                continue;
1008
1009            List<sourceColumn> sources = tempRelation.getSources();
1010            if (sources != null) {
1011                if (relationships.size() * sources.size() > 5000) {
1012                    System.out.println("The relationship is too huge, skip the join trace.");
1013                    continue;
1014                }
1015            }
1016
1017            String tempColumnId = tempRelation.getTarget().getId();
1018            String tempParentId = tempRelation.getTarget().getParent_id();
1019            tempColumnId = convertColumnId(tableColumns,
1020                    tempColumnId,
1021                    tempParentId);
1022            if (tempColumnId.equals(targetColumnId)) {
1023                if (tempRelation.getType().equals(RelationshipType.join.name())) {
1024                    return true;
1025                } else if (tempRelation.getType()
1026                        .equals(RelationshipType.fdd.name())) {
1027                    if (level < 2
1028                            && traceJoin(tempRelation,
1029                            relationships,
1030                            tableColumns,
1031                            level + 1)) {
1032                        return true;
1033                    }
1034                }
1035            }
1036
1037            if (sources != null) {
1038                for (int j = 0; j < sources.size(); j++) {
1039                    if ("constant".equals(sources.get(j).getColumn_type())) {
1040                        continue;
1041                    }
1042                    tempColumnId = sources.get(j).getId();
1043                    tempParentId = sources.get(j).getParent_id();
1044                    tempColumnId = convertColumnId(tableColumns,
1045                            tempColumnId,
1046                            tempParentId);
1047                    if (tempColumnId.equals(targetColumnId)) {
1048                        if (tempRelation.getType()
1049                                .equals(RelationshipType.join.name())) {
1050                            return true;
1051                        } else if (tempRelation.getType()
1052                                .equals(RelationshipType.fdd.name())) {
1053                            if (level < 2
1054                                    && traceJoin(tempRelation,
1055                                    relationships,
1056                                    tableColumns,
1057                                    level + 1)) {
1058                                return true;
1059                            }
1060                        }
1061                    }
1062                }
1063            }
1064        }
1065
1066        return false;
1067    }
1068
1069    private String convertColumnId(
1070            Map<String, Map<String, List<column>>> tableColumns,
1071            String columnId, String parentId) {
1072        if (tableColumns.containsKey(parentId)) {
1073            Map<String, List<column>> columnMap = tableColumns.get(parentId);
1074            Iterator<List<column>> iter = columnMap.values().iterator();
1075            for (int i = 0; i < columnMap.size(); i++) {
1076                List<column> columns = iter.next();
1077                for (int j = 0; j < columns.size(); j++) {
1078                    column column = columns.get(j);
1079                    if (column.getId().equals(columnId)) {
1080                        return parentId + "-index-" + i;
1081                    }
1082                }
1083            }
1084        }
1085        if (parentId != null) {
1086            return parentId + "-id-" + columnId;
1087        } else
1088            return columnId;
1089    }
1090
1091    private String getShortLabel(String label, int length) {
1092        int index = length / 2 - 1;
1093        return (label.substring(0, index - 1) + "..." + label.substring(label.length()
1094                - (index + 1)));
1095    }
1096
1097}