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