[Fortify] Report Generator

fortify_ssc_report.java

/*********************************************************************
 *
 * Opentext Fortify SSC DB 기반 리포트를 CSV 또는 XLS로 출력
 * (취약점의 경로 및 라인번호, SSC 링크까지 상세히 출력)
 *
 * 설명     : Fortify SSC DB에 접속하여 Application에 대한 취약점
 *            리포트 작성
 *            실행 전 ssc_info.conf 를 편집하여 설정 셋팅
 * 빌드 방법: javac -encoding utf-8 -cp lib/* fortify_ssc_report.java
 * 실행 방법: java -cp lib/* fortify_ssc_report -v -i <AppID>
 *            -i <AppID> :특정 애플리케이션 버전에 대한 취약점만 출력
 *                        생략 시 전 애플리케이션이 대상
 *            -v: 결과를 stdout으로 출력
 * 작성자   : 이존석 (hasu0707@esvali.com)
 *
 ********************************************************************/

import org.apache.poi.common.usermodel.Hyperlink;
import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFHyperlink;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFHyperlink;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;

public class fortify_ssc_report {
    private static final String thisAppName = "fortify_ssc_report";
    public static boolean verbose = false;
    public static boolean isAllApplications = true;
    public static String applicationID = "0";
    public static HashMap < String, String > propMap = new HashMap < String, String > ();

    /**
     **********************************************************
     * 사용법 출력
     **********************************************************
     */
    public static void usage() {
        System.out.println(thisAppName);
        System.out.println("  -i <SSC Application ID> : Application ID to report on.");
        System.out.println("  -v : verbose");
    }

    /**
     **********************************************************
     * 설정 파일 읽기
     **********************************************************
     */
    public static int readPropertyFile(String fileName) {
        Properties prop = new Properties();

        try (FileInputStream fis = new FileInputStream(fileName)) {
            prop.load(fis);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            System.exit(1);
        } catch (IOException ex) {
            ex.printStackTrace();
            System.exit(2);
        }

        // 설정 값 읽어오기
        propMap.put("title", prop.getProperty("title"));
        propMap.put("db_jdbc_addr", prop.getProperty("db_jdbc_addr"));
        propMap.put("db_type", prop.getProperty("db_type"));
        propMap.put("db_name", prop.getProperty("db_name"));
        propMap.put("db_id", prop.getProperty("db_id"));
        propMap.put("db_pw", prop.getProperty("db_pw"));
        propMap.put("report_type", prop.getProperty("report_type"));
        propMap.put("ssc_url", prop.getProperty("ssc_url"));
        propMap.put("jdbc_class_name", prop.getProperty("jdbc_class_name"));
        propMap.put("filterset", prop.getProperty("filterset"));
        propMap.put("groupingtype", prop.getProperty("groupingtype"));
        propMap.put("orderby", prop.getProperty("orderby"));

        // 설정에 없는 경우 기본값 셋팅
        if (propMap.get("title") == null)
            propMap.put("title", "FORTIFY REPORT");
        if (propMap.get("db_jdbc_addr") == null)
            propMap.put("db_jdbc_addr", "jdbc:mysql://localhost:3306");
        if (propMap.get("db_type") == null)
            propMap.put("db_type", "mysql");
        if (propMap.get("db_name") == null)
            propMap.put("db_name", "/db_ssc_2320");
        if (propMap.get("db_id") == null)
            propMap.put("db_id", "root");
        if (propMap.get("db_pw") == null)
            propMap.put("db_pw", "root");
        if (propMap.get("report_type") == null)
            propMap.put("report_type", "xls");
        if (propMap.get("ssc_url") == null)
            propMap.put("ssc_url", "http://localhost:8080/ssc");
        if (propMap.get("jdbc_class_name") == null)
            propMap.put("jdbc_class_name", "com.mysql.cj.jdbc.Driver");
        if (propMap.get("filterset") == null)
            propMap.put("filterset", "32142c2d-3f7f-4863-a1bf-9b1e2f34d2ed");
        if (propMap.get("groupingtype") == null)
            propMap.put("groupingtype", "11111111-1111-1111-1111-111111111165");
        if (propMap.get("orderby") == null)
            propMap.put("orderby", "friority");

        return 0;
    }

    /**
     **********************************************************
     * 명령행 파싱
     * 반환값: 리포팅 할 ApplicationID
     **********************************************************
     */
    public static int parseCommandLine(String[] optionString) {
        // -i <애플리케이션 번호> : 리포팅할 애플리케이션 ID
        // -v : 리포팅 생성 과정 출력
        for (int i = 0; i < optionString.length; i++) {
            //debug
            System.out.println("OPT:"+ optionString[i]);
            if ("-v".equals(optionString[i]) || "--verbose".equals(optionString[i])) {
                verbose = true;
            } else if ("-i".equals(optionString[i]) || "--id".equals(optionString[i])) {
                if (i + 1 < optionString.length) {
                    applicationID = optionString[++i];
                    isAllApplications = false;
                } else {
                    System.err.println("Error: missing application ID");
                    usage();
                    System.exit(1);
                }
            } else {
                System.err.println("Error: unrecognized argument: " + optionString[i]);
                usage();
                System.exit(1);
            }
        }

        return Integer.parseInt(applicationID);
    }

    /**
     **********************************************************
     * SQL 쿼리 스트링 작성
     **********************************************************
     */
    public static String getSQLString(String db_type) {
        // SQL 정의
        // filterset.enabled = 'N'이면 QuickView 모드
        String sqlString = null;

        switch (db_type) {
            case "mysql":
                sqlString =
                    "SELECT projectversion.id   AS '01',\n" +
                    "       issue.id            AS '02',\n" +
                    "       issue.issueInstanceId    AS '03',\n" +
                    "       project.name        AS '04',\n" +
                    "       projectversion.name AS '05',\n" +
                    "       folder.name         AS '06',\n" +
                    "       issue.kingdom       AS '07',\n" +
                    "       issue.issueType     AS '08',\n" +
                    "       issue.issueSubtype  AS '09',\n" +
                    "       issue.fileName      AS '10',\n" +
                    "       issue.packageName   AS '11',\n" +
                    "       issue.className     AS '12',\n" +
                    "       issue.functionName  AS '13',\n" +
                    "       issue.lineNumber    AS '14'\n" +
                    "FROM   issuecache\n" +
                    "       LEFT JOIN issue\n" +
                    "              ON issuecache.issue_id = issue.id\n" +
                    "       LEFT JOIN projectversion\n" +
                    "              ON issuecache.projectVersion_id = projectversion.id\n" +
                    "       LEFT JOIN project\n" +
                    "              ON projectversion.project_id = project.id AND projectversion.active = 'Y'\n" +
                    "       LEFT JOIN folder\n" +
                    "              ON issuecache.folder_id = folder.id\n" +
                    "       LEFT JOIN filterset\n" +
                    "              ON issuecache.filterSet_id = filterset.id\n" +
                    "WHERE  filterset.enabled = 'N'\n" +
                    "       AND issuecache.hidden = 'N'\n" +
                    "       AND issue.suppressed = 'N'\n" +
                    "       AND issue.scanStatus <> 'REMOVED'\n" +
                    "       AND issue.friority <> 'Medium'\n" +
                    "       AND issue.friority <> 'Low'\n" +
/*
                    "GROUP  BY project.name,\n" +
                    "          projectversion.name,\n" +
                    "          folder.name,\n" +
                    "          issue.kingdom,\n" +
                    "          issue.issueType,\n" +
                    "          issue.issueSubtype,\n" +
                    "          issue.fileName,\n" +
                    "          issue.packageName,\n" +
                    "          issue.className,\n" +
                    "          issue.functionName,\n" +
                    "          issue.lineNumber\n" +
*/
                    "ORDER BY  project.name ASC,\n" +
                    "          projectversion.name ASC,\n" +
                    "          folder.name ASC,\n" +
                    "          issue.kingdom ASC,\n" +
                    "          issue.fileName ASC,\n" +
                    "          issue.issueType ASC,\n" +
                    "          issue.issueSubtype ASC";
                break;
            case "mssql":
                sqlString =
                    "SELECT projectversion.id   AS '01',\n" +
                    "       issue.id            AS '02',\n" +
                    "       issue.issueInstanceId    AS '03',\n" +
                    "       project.name        AS '04',\n" +
                    "       projectversion.name AS '05',\n" +
                    "       folder.name         AS '06',\n" +
                    "       issue.kingdom       AS '07',\n" +
                    "       issue.issueType     AS '08',\n" +
                    "       issue.issueSubtype  AS '09',\n" +
                    "       issue.fileName      AS '10',\n" +
                    "       issue.packageName   AS '11',\n" +
                    "       issue.className     AS '12',\n" +
                    "       issue.functionName  AS '13',\n" +
                    "       issue.lineNumber    AS '14'\n" +
                    "FROM   issuecache\n" +
                    "       LEFT JOIN issue\n" +
                    "              ON issuecache.issue_id = issue.id\n" +
                    "       LEFT JOIN projectversion\n" +
                    "              ON issuecache.projectVersion_id = projectversion.id\n" +
                    "       LEFT JOIN project\n" +
                    "              ON projectversion.project_id = project.id AND projectversion.active = 'Y'\n" +
                    "       LEFT JOIN folder\n" +
                    "              ON issuecache.folder_id = folder.id\n" +
                    "       LEFT JOIN filterset\n" +
                    "              ON issuecache.filterSet_id = filterset.id\n" +
                    "WHERE  filterset.enabled = 'N'\n" +
                    "       AND issuecache.hidden = 'N'\n" +
                    "       AND issue.suppressed = 'N'\n" +
                    "       AND issue.scanStatus <> 'REMOVED'\n" +
                    "       AND issue.friority <> 'Medium'\n" +
                    "       AND issue.friority <> 'Low'\n" +
/*
                    "GROUP  BY project.name,\n" +
                    "          projectversion.name,\n" +
                    "          folder.name,\n" +
                    "          issue.kingdom,\n" +
                    "          issue.issueType,\n" +
                    "          issue.issueSubtype,\n" +
                    "          issue.fileName,\n" +
                    "          issue.packageName,\n" +
                    "          issue.className,\n" +
                    "          issue.functionName,\n" +
                    "          issue.lineNumber\n" +
*/
                    "ORDER BY  project.name ASC,\n" +
                    "          projectversion.name ASC,\n" +
                    "          folder.name ASC,\n" +
                    "          issue.kingdom ASC,\n" +
                    "          issue.fileName ASC,\n" +
                    "          issue.issueType ASC,\n" +
                    "          issue.issueSubtype ASC";
                break;
            case "oracle" :
                sqlString =
                    "SELECT projectversion.id,\n" +
                    "       issue.id,\n" +
                    "       issue.issueInstanceId,\n" +
                    "       project.name,\n" +
                    "       projectversion.name,\n" +
                    "       folder.name,\n" +
                    "       issue.kingdom,\n" +
                    "       issue.issueType,\n" +
                    "       issue.issueSubtype,\n" +
                    "       issue.fileName,\n" +
                    "       issue.packageName,\n" +
                    "       issue.className,\n" +
                    "       issue.functionName,\n" +
                    "       issue.lineNumber\n" +
                    "FROM   issuecache\n" +
                    "       LEFT JOIN issue\n" +
                    "              ON issuecache.issue_id = issue.id\n" +
                    "       LEFT JOIN projectversion\n" +
                    "              ON issuecache.projectVersion_id = projectversion.id\n" +
                    "       LEFT JOIN project\n" +
                    "              ON projectversion.project_id = project.id AND projectversion.active = 'Y'\n" +
                    "       LEFT JOIN folder\n" +
                    "              ON issuecache.folder_id = folder.id\n" +
                    "       LEFT JOIN filterset\n" +
                    "              ON issuecache.filterSet_id = filterset.id\n" +
                    "WHERE  filterset.enabled = 'N'\n" +
                    "       AND issuecache.hidden = 'N'\n" +
                    "       AND issue.suppressed = 'N'\n" +
                    "       AND issue.scanStatus <> 'REMOVED'\n" +
                    "       AND issue.friority <> 'Medium'\n" +
                    "       AND issue.friority <> 'Low'\n" +
/*
                    "GROUP  BY project.name,\n" +
                    "          projectversion.name,\n" +
                    "          folder.name,\n" +
                    "          issue.kingdom,\n" +
                    "          issue.issueType,\n" +
                    "          issue.issueSubtype,\n" +
                    "          issue.fileName,\n" +
                    "          issue.packageName,\n" +
                    "          issue.className,\n" +
                    "          issue.functionName,\n" +
                    "          issue.lineNumber\n" +
*/
                    "ORDER BY  project.name ASC,\n" +
                    "          projectversion.name ASC,\n" +
                    "          folder.name ASC,\n" +
                    "          issue.kingdom ASC,\n" +
                    "          issue.fileName ASC,\n" +
                    "          issue.issueType ASC,\n" +
                    "          issue.issueSubtype ASC";
                break;
            default :
                System.out.println("ERROR: DB Type is unknown-"+db_type);
                System.exit(1);
        }

        return sqlString;
    }

    /**
     **********************************************************
     * CSV 파일에 타이틀 줄을 써 넣는다.
     **********************************************************
     */
    public static String getSSCHyperLink(String AppID, String issueID) {
        String hyperLink = null;

        hyperLink = propMap.get("ssc_url");
        hyperLink = hyperLink + "/html/ssc/version/";
        hyperLink = hyperLink + AppID + "/";
        hyperLink = hyperLink + "audit?q=";

        hyperLink = hyperLink + "%5Binstance%20id%5D%3A" + issueID + "%20";
        hyperLink = hyperLink + "%5Banalysis%20type%5D%3ASCA&filterset=" + propMap.get("filterset") + "&";
        hyperLink = hyperLink + "groupingtype=" + propMap.get("groupingtype") + "&";
        hyperLink = hyperLink + "orderby=" + propMap.get("orderby") + "&";
        hyperLink = hyperLink + "issue=" + issueID + "&";
        hyperLink = hyperLink + "enginetype=SCA&viewTab=code";

        return hyperLink;
    }

    /**
     **********************************************************
     * CSV 파일에 타이틀 줄을 써 넣는다.
     **********************************************************
     */
    public static int csvWriteTitle(FileWriter fileDesc) {
        String csvTitle = "ID,APPLICATION,VERSION,FRIORITY,KINGDOM,ISSUE_TYPE,ISSUE_SUBTYPE,FILE,FUNCTION(PACKAGE|CLASS|METHOD),LINE,HYPER_LINK\n";

        try {
            fileDesc.write(csvTitle);
        } catch (Exception e) {
            System.err.println("ERROR: write - " + e.getMessage());
            e.printStackTrace();
        }

        return 0;
    }

    /**
     **********************************************************
     * CSV 파일에 목록을 작성한다.
     **********************************************************
     */
    public static int csvWriteList(ResultSet resultQuery, FileWriter fileDesc) {
        int listCount;
        boolean isWrite = false;
        String sinkString = null;

        listCount = 0;
        try {
            while (resultQuery.next()) {
                // 지정된 애플리케이션 번호가 있으면 그것만 출력
                isWrite = false;
                if (isAllApplications) {
                    isWrite = true;
                } else {
                    if (applicationID.equals(resultQuery.getString(1))) {
                        isWrite = true;
                    }
                }

                if (isWrite) {
                    // 함수명 문자열 완성
                    sinkString = resultQuery.getString(11) + "|" + resultQuery.getString(12) + "|" + resultQuery.getString(13);

                    String csv_data = String.format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
                        resultQuery.getString(2),
                        resultQuery.getString(4),
                        resultQuery.getString(5),
                        resultQuery.getString(6),
                        resultQuery.getString(7),
                        resultQuery.getString(8),
                        resultQuery.getString(9),
                        resultQuery.getString(10),
                        sinkString,
                        resultQuery.getString(14),
                        getSSCHyperLink(resultQuery.getString(1), resultQuery.getString(3)));
                    try {
                        fileDesc.write(csv_data);
                        if (verbose) {
                            System.out.println(csv_data);
                        }
                        listCount += 1;
                    } catch (IOException e) {
                        System.err.println("ERROR: fileDesc.write - " + e.getMessage());
                        e.printStackTrace();
                    }
                }
            }
        } catch (SQLException e) {
            System.err.println("ERROR: resultQuery.getString - " + e.getMessage());
            e.printStackTrace();
        }

        return listCount;
    }

    /**
     **********************************************************
     * SQL 쿼리 결과를 CSV 파일로 저장
     **********************************************************
     */
    public static int csvWrite(ResultSet resultQuery) {
        FileWriter fileDesc = null;
        int listCount;

        try {
            fileDesc = new FileWriter(thisAppName + ".csv");
        } catch (IOException e) {
            System.err.println("ERROR:" + e.getMessage());
            e.printStackTrace();
        }
        csvWriteTitle(fileDesc);

        listCount = csvWriteList(resultQuery, fileDesc);
        try {
            fileDesc.close();
        } catch (IOException e) {
            System.err.println("ERROR:" + e.getMessage());
            e.printStackTrace();
        }

        return listCount;
    }

    /**
     **********************************************************
     * excel 파일에 타이틀 줄을 써 넣는다.
     **********************************************************
     */
    public static int xlsWriteTitle(XSSFWorkbook xlsWorkBook, XSSFSheet xlsSheet) {
        int rowCount = 0;
        CellStyle cellStyle1 = xlsWorkBook.createCellStyle();
        CellStyle cellStyle2 = xlsWorkBook.createCellStyle();
        CellStyle cellStyle3 = xlsWorkBook.createCellStyle();
        XSSFFont cellFont1 = xlsWorkBook.createFont();
        XSSFFont cellFont2 = xlsWorkBook.createFont();
        XSSFFont cellFont3 = xlsWorkBook.createFont();
        Map<String, Object[]> titleData = new TreeMap<>();

        // 제목
        cellFont1.setFontHeightInPoints((short) 12);
        cellFont1.setFontName("Gulim");
        cellFont1.setBold(true);
        cellFont1.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());

        // 주의 사항
        cellFont2.setFontHeightInPoints((short) 9);
        cellFont2.setFontName("Gulim");
        cellFont2.setBold(false);
        cellFont2.setColor(HSSFColor.HSSFColorPredefined.RED.getIndex());

        // 컬럼 명
        cellFont3.setFontHeightInPoints((short) 9);
        cellFont3.setFontName("Gulim");
        cellFont3.setBold(true);
        cellFont3.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());

        cellStyle1.setFont(cellFont1);
        cellStyle1.setWrapText(false);
        cellStyle2.setFont(cellFont2);
        cellStyle2.setWrapText(false);
        cellStyle3.setFont(cellFont3);
        cellStyle3.setWrapText(false);

        // 제목 추가
        cellStyle1.setFont(cellFont1);
        XSSFRow titleRow1 = xlsSheet.createRow(rowCount++);
        Cell titleCell1 = titleRow1.createCell(0);
        titleCell1.setCellStyle(cellStyle1);
        titleCell1.setCellValue(propMap.get("title"));

        // 주의 사항
        XSSFRow titleRow2 = xlsSheet.createRow(rowCount++);
        Cell titleCell2 = titleRow2.createCell(0);
        titleCell2.setCellStyle(cellStyle2);
        titleCell2.setCellValue("(**) " + propMap.get("ssc_url") + " 에 사번으로 로그인 후 HYPER_LINK를 클릭하면 상세 내용 확인이 가능 합니다.");

        titleData.put("1", new Object[]{"ID", "APPLICATION", "VERSION", "FRIORITY", "KINGDOM", "ISSUE_TYPE", "ISSUE_SUBTYPE", "FILE", "FUNCTION(PACKAGE|CLASS|METHOD)", "LINE", "HYPER_LINK"});

        // data에서 keySet를 가져온다. 이 Set 값들을 조회하면서 데이터들을 sheet에 입력한다.
        Set<String> titleKeySet = titleData.keySet();
        int rowNum = rowCount++;

        // 알아야할 점은 TreeMap을 통해 생성된 keySet는 for를 조회 시, 키 값이 오름차순으로 조회된다.
        for (String keyString : titleKeySet) {
            Row rowValue = xlsSheet.createRow(rowNum++);
            Object[] cellObjectArr = titleData.get(keyString);
            int cellNum = 0;
            for (Object cellObject : cellObjectArr) {
                Cell cellVaule = rowValue.createCell(cellNum++);
                if (cellObject instanceof String) {
                    cellVaule.setCellValue((String)cellObject);
                } else if (cellObject instanceof Integer) {
                    cellVaule.setCellValue((Integer)cellObject);
                }
                cellVaule.setCellStyle(cellStyle3);
            }
        }

        return 0;
    }

    /**
     **********************************************************
     * excel 파일에 목록을 작성한다.
     **********************************************************
     */
    public static int xlsWriteList(ResultSet resultQuery, XSSFWorkbook xlsWorkBook, XSSFSheet xlsSheet) {
        int listCount = 0;
        boolean isWrite = false;
        String sinkString = null;
        CreationHelper createHelper = xlsWorkBook.getCreationHelper();
        CellStyle cellStyle = xlsWorkBook.createCellStyle();
        XSSFFont cellFont = xlsWorkBook.createFont();
        Map<String, Object[]> titleData = new TreeMap<>();

        cellFont.setFontHeightInPoints((short) 9); // 폰트 크기
        cellFont.setFontName("Gulim");             // 폰트
        cellStyle.setFont(cellFont);
        cellStyle.setWrapText(true);

        try {
            while (resultQuery.next()) {
                // 지정된 애플리케이션 번호가 있으면 그것만 출력
                isWrite = false;
                if (isAllApplications) {
                    isWrite = true;
                } else {
                    if (applicationID.equals(resultQuery.getString(1))) {
                        isWrite = true;
                    }
                }

                if (isWrite) {
                    // 함수명 문자열 완성
                    sinkString = resultQuery.getString(11) + "|" + resultQuery.getString(12) + "|" + resultQuery.getString(13);

                    // SSC 하이퍼 링크 생성
                    XSSFHyperlink sscHyperLink = (XSSFHyperlink)createHelper.createHyperlink(HyperlinkType.URL);
                    sscHyperLink.setAddress(getSSCHyperLink(resultQuery.getString(1), resultQuery.getString(3)));

                    titleData.put("1", new Object[]{
                        resultQuery.getString(2),
                        resultQuery.getString(4),
                        resultQuery.getString(5),
                        resultQuery.getString(6),
                        resultQuery.getString(7),
                        resultQuery.getString(8),
                        resultQuery.getString(9),
                        resultQuery.getString(10),
                        sinkString,
                        resultQuery.getString(14),
                        "View"
                        });

                    // data에서 keySet를 가져온다. 이 Set 값들을 조회하면서 데이터들을 sheet에 입력한다.
                    Set<String> titleKeySet = titleData.keySet();
                    int rowNum = listCount + 3;

                    // 알아야할 점은 TreeMap을 통해 생성된 keySet는 for를 조회 시, 키 값이 오름차순으로 조회된다.
                    for (String keyString : titleKeySet) {
                        Row rowValue = xlsSheet.createRow(rowNum++);
                        Object[] cellObjectArr = titleData.get(keyString);
                        int cellNum = 0;
                        if (verbose) {
                            System.out.printf("Writing excel row %d\n", listCount);
                        }
                        for (Object cellObject : cellObjectArr) {
                            Cell cellVaule = rowValue.createCell(cellNum++);
                            if (cellObject instanceof String) {
                                cellVaule.setCellValue((String)cellObject);
                            } else if (cellObject instanceof Integer) {
                                cellVaule.setCellValue((Integer)cellObject);
                            }
                            // 링크 적용
                            if (cellNum == 11) {
                                cellVaule.setHyperlink(sscHyperLink);
                            }
                            // 셀 스타일 적용
                            cellVaule.setCellStyle(cellStyle);
                            // 자동 컬럼넓이 적용
                            xlsSheet.autoSizeColumn(cellNum);
                        }
                    }
                    listCount += 1;
                }
            }
        } catch (SQLException e) {
            System.err.println("ERROR: resultQuery.getString - " + e.getMessage());
            e.printStackTrace();
        }

        return listCount;
    }

    /**
     **********************************************************
     * SQL 쿼리 결과를 excel 파일로 저장
     **********************************************************
     */
    public static int xlsWrite(ResultSet resultQuery) {
        int listCount;

        // 빈 Workbook 생성
        XSSFWorkbook xlsWorkBook = new XSSFWorkbook();

        // 빈 Sheet를 생성
        XSSFSheet xlsSheet = xlsWorkBook.createSheet("Fortify Report");
        xlsWriteTitle(xlsWorkBook, xlsSheet);
        listCount = xlsWriteList(resultQuery, xlsWorkBook, xlsSheet);

        try {
            FileOutputStream fileDesc = new FileOutputStream(thisAppName + ".xls");
            xlsWorkBook.write(fileDesc);
            fileDesc.close();
        } catch (IOException e) {
            System.err.println("ERROR:" + e.getMessage());
            e.printStackTrace();
        }

        return listCount;
    }

    /**
     **********************************************************
     * DB에 접속하여 SQL문을 실행한다.
     **********************************************************
     */
    public static int runSQLQuery() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet resultQuery = null;
        String sqlQueryString = null;
        int resultCount = 0;

        // DB 종류에 맞는 JDBC 동적 로딩
        try {
            Class.forName(propMap.get("jdbc_class_name"));
        } catch (ClassNotFoundException e) {
            System.err.println("ERROR: Class.forName - " + e.getMessage());
            e.printStackTrace();
        }

        // DB 접속
        try {
            conn = DriverManager.getConnection(
                propMap.get("db_jdbc_addr") + propMap.get("db_name"),
                propMap.get("db_id"),
                propMap.get("db_pw"));
        } catch (SQLException e) {
            System.err.println("ERROR: DriverManager.getConnection - " + e.getMessage());
            e.printStackTrace();
        }

        // SQL 작성 및 실행
        try {
            stmt = conn.createStatement();
            sqlQueryString = getSQLString("mysql");
            System.out.println("-- SQL:\n" + sqlQueryString + "\n");
            resultQuery = stmt.executeQuery(sqlQueryString);
            switch (propMap.get("report_type")) {
                case "csv":
                    resultCount = csvWrite(resultQuery);
                    break;
                case "xls":
                    resultCount = xlsWrite(resultQuery);
                    break;
                default:
                    System.err.println("ERROR: Unknown report type.");
            }
            resultQuery.close();
            stmt.close();
            conn.close();
        } catch (SQLException e) {
            System.err.println("ERROR: executeQuery - " + e.getMessage());
            e.printStackTrace();
        }

        return resultCount;
    }

    /**
     **********************************************************
     * main
     **********************************************************
     */
    public static void main(String[] args) throws Exception {
        int arg1, resultCount = 0;
        String propFileName = "ssc_info.conf";

        parseCommandLine(args);
        readPropertyFile(propFileName);
        if (applicationID != "0") {
            System.out.printf("APPLICATION ID: %s\n", applicationID);
        }
        resultCount = runSQLQuery();
        System.out.println("Issue total: " + resultCount + "\n");
    }
}

ssc_info.conf

# MySQL
title=FORTIFY REPORT
db_type=mysql
db_jdbc_addr=jdbc:mysql://10.10.10.149:3306
db_name=/db_ssc_2222
db_id=u_ssc
db_pw=<Password>
jdbc_class_name=com.mysql.cj.jdbc.Driver
report_type=xls
ssc_url=http://10.10.10.43:8080/ssc
filterset=32142c2d-3f7f-4863-a1bf-9b1e2f34d2ed
groupingtype=11111111-1111-1111-1111-111111111165
orderby=friority

# Microsoft SQL
#title=FORTIFY REPORT
#db_type=mssql
#db_jdbc_addr=jdbc:sqlserver://10.10.10.105;
#db_name=DatabaseName=db_ssc_2020
#db_id=sa
#db_pw=<Password>
#jdbc_class_name=com.microsoft.sqlserver.jdbc.SQLServerDriver
#report_type=csv
#ssc_url=http://10.10.10.43:8080/ssc
#filterset=32142c2d-3f7f-4863-a1bf-9b1e2f34d2ed
#groupingtype=11111111-1111-1111-1111-111111111165
#orderby=friority

# Oracle
#title=FORTIFY REPORT
#db_type=oracle
#db_jdbc_addr=jdbc:oracle:thin:@10.10.10.105:1521
#db_name=/ORCLCDB
#db_id=u_ssc_2310
#db_pw=<Password>
#jdbc_class_name=oracle.jdbc.driver.OracleDriver
#report_type=csv
#ssc_url=http://10.10.10.43:8080/ssc
#filterset=32142c2d-3f7f-4863-a1bf-9b1e2f34d2ed
#groupingtype=11111111-1111-1111-1111-111111111165
#orderby=friority

RUN.BAT

@ECHO OFF
REM ########################################################################
REM #
REM # fortify_ssc_report의 윈도우용 실행 스크립트
REM #
REM ########################################################################

REM =======================================
REM = CODEPAGE를 UTF-8로 변경
REM =======================================
CHCP 65001 1> NUL 2> NUL
CLS

REM ########################################################################
REM #
REM # 환경 변수 설정 (첫 실행시 반드시 환경에 맞게 수정요망)
REM # 윈도우 스케줄러 실행을 위해서는 WORK_PATH에 절대 경로 설정
REM #
REM ########################################################################
SET CLASS_NAME1=fortify_ssc_report
SET RUN_COMPILE=1
SET "WORK_PATH=%CD%"
SET "CSV_RESULT_PATH=%WORK_PATH%\reports"
SET "JAVA_HOME=C:\PortableApps\jdk-17.0.9"
SET "CLASSPATH=.;%WORK_PATH%\lib\*"
SET "CURRENT_DIR=%CD%"

CD /D "%WORK_PATH%"
IF NOT EXIST %CSV_RESULT_PATH% MKDIR %CSV_RESULT_PATH%
REM ########################################################################
REM #
REM # 날짜/시간 문자열 만들기
REM #
REM ########################################################################
SET TIMESTAMP_VAL=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%_%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%
SET TIMESTAMP_VAL=%TIMESTAMP_VAL: =0%

REM ########################################################################
REM #
REM # JDK 경로 추가
REM #
REM ########################################################################
SET PATH=%JAVA_HOME%\bin;%PATH%

REM ########################################################################
REM #
REM # 빌드 및 실행
REM #
REM ########################################################################
IF %RUN_COMPILE% == 1 (
  javac -encoding utf-8 -cp "%CLASSPATH%" "%CLASS_NAME1%.java"
)
ECHO.
ECHO Running %CLASS_NAME1%...
ECHO.
java -cp "%CLASSPATH%" "%CLASS_NAME1%" %1 %2 %3 %4 %5

REM ########################################################################
REM #
REM # 출력된 CSV 파일을 리포트 디렉토리로 이동시킨다.
REM #
REM ########################################################################
MOVE /Y "%CLASS_NAME1%.xls" "%CSV_RESULT_PATH%\%TIMESTAMP_VAL%-%CLASS_NAME1%.xls"

run.sh

#!/bin/bash
########################################################################
#
# fortify_ssc_report의 리눅스용 실행 스크립트
#
########################################################################

########################################################################
#
# 환경 변수 설정 (첫 실행시 반드시 환경에 맞게 수정요망)
# crontab 실행을 위해서는 WORK_PATH에 절대 경로 설정
#
########################################################################
CLASS_NAME1="fortify_ssc_report"
RUN_COMPILE=1
WORK_PATH=`pwd -P`
CSV_RESULT_PATH="${WORK_PATH}/reports"
JAVA_HOME="/usr"
CLASSPATH=".:${JAVA_HOME}/lib/tools.jar:${WORK_PATH}/lib/*"
CURRENT_DIR=`pwd -P`
DATETIME_STR=`date -u +%Y%m%d_%H%M%S`

run_class ()
{
  ########################################################################
  #
  # 빌드 및 실행
  #
  ########################################################################
  if [ ${RUN_COMPILE} = 1 ]
  then
    javac -encoding utf-8 -cp "${CLASSPATH}" ${CLASS_NAME1}.java
  fi
  echo
  echo "Running ${CLASS_NAME1}..."
  echo
  java -cp "${CLASSPATH}" ${CLASS_NAME1} $1 $2 $3 $4 $5
  ########################################################################
  #
  # 출력된 CSV 파일을 리포트 디렉토리로 이동시킨다.
  #
  ########################################################################
  OUTPUT_FILE="${CSV_RESULT_PATH}/${DATETIME_STR}-${CLASS_NAME1}.xls"
  if [ -f "${CLASS_NAME1}.xls" ]
  then
    #iconv -f "UTF-8" -t "EUC-KR" "${CLASS_NAME1}.csv" > "${OUTPUT_FILE}"
    #rm -f "${CLASS_NAME1}.csv"
    mv -fv "${CLASS_NAME1}.xls" "${OUTPUT_FILE}"
  fi
  if [ -f "${OUTPUT_FILE}" ]
  then
    chmod 644 "${OUTPUT_FILE}"
  fi
}

if [ ! -d "${WORK_PATH}" ]
then
  mkdir -p "${WORK_PATH}"
fi

if [ ! -d "${CSV_RESULT_PATH}" ]
then
  mkdir -p "${CSV_RESULT_PATH}"
fi

########################################################################
#
# 기능별로 하나씩 실행 (변수 정의를 주석처리 하면 기능 비 활성화)
#
########################################################################
cd "${WORK_PATH}"
PATH=${JAVA_HOME}/bin:${JAVA_HOME}/jre/bin:${PATH}
cd ${WORK_PATH}
run_class $1 $2 $3 $4 $5

cd ${CURRENT_DIR}
exit $?
위로 스크롤