Java tutorial
/** * Copyright (c) 2016 Source Auditor Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.spdx.spdxspreadsheet; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spdx.rdfparser.InvalidSPDXAnalysisException; import org.spdx.rdfparser.SpdxDocumentContainer; import org.spdx.rdfparser.license.AnyLicenseInfo; import org.spdx.rdfparser.license.LicenseInfoFactory; import org.spdx.rdfparser.model.Annotation; import org.spdx.rdfparser.model.Relationship; import org.spdx.rdfparser.model.SpdxElement; import org.spdx.rdfparser.model.SpdxFile; import org.spdx.rdfparser.model.SpdxSnippet; import org.spdx.rdfparser.model.pointer.ByteOffsetPointer; import org.spdx.rdfparser.model.pointer.LineCharPointer; import org.spdx.rdfparser.model.pointer.SinglePointer; import org.spdx.rdfparser.model.pointer.StartEndPointer; import com.google.common.collect.Maps; /** * Sheet to hold all snippet information * @author Gary O'Neall * */ public class SnippetSheet extends AbstractSheet { static final Logger logger = LoggerFactory.getLogger(SnippetSheet.class); static final int ID_COL = 0; static final int NAME_COL = ID_COL + 1; static final int SNIPPET_FROM_FILE_ID_COL = NAME_COL + 1; static final int BYTE_RANGE_COL = SNIPPET_FROM_FILE_ID_COL + 1; static final int LINE_RANGE_COL = BYTE_RANGE_COL + 1; static final int CONCLUDED_LICENSE_COL = LINE_RANGE_COL + 1; static final int LICENSE_INFO_IN_SNIPPET_COL = CONCLUDED_LICENSE_COL + 1; static final int LICENSE_COMMENT_COL = LICENSE_INFO_IN_SNIPPET_COL + 1; static final int COPYRIGHT_COL = LICENSE_COMMENT_COL + 1; static final int COMMENT_COL = COPYRIGHT_COL + 1; static final int USER_DEFINED_COLS = COMMENT_COL + 1; static final int NUM_COLS = USER_DEFINED_COLS + 1; static final boolean[] REQUIRED = new boolean[] { true, false, true, true, false, false, false, false, false, false, false }; static final String[] HEADER_TITLES = new String[] { "ID", "Name", "From File ID", "Byte Range", "Line Range", "License Concluded", "License Info in Snippet", "License Comments", "Snippet Copyright Text", "Comment", "User Defined Columns..." }; static final int[] COLUMN_WIDTHS = new int[] { 25, 25, 25, 40, 40, 60, 60, 60, 60, 60, 40 }; static final boolean[] LEFT_WRAP = new boolean[] { false, false, false, false, false, true, true, true, true, true, true }; static final boolean[] CENTER_NOWRAP = new boolean[] { true, true, true, true, true, false, false, false, false, false, false }; private static Pattern NUMBER_RANGE_PATTERN = Pattern.compile("(\\d+):(\\d+)"); /** * Hashmap of the snippet ID to SPDX snipet */ Map<String, SpdxSnippet> snippetCache = Maps.newHashMap(); /** * @param workbook * @param snippetSheetName */ public SnippetSheet(Workbook workbook, String snippetSheetName) { super(workbook, snippetSheetName); } /* (non-Javadoc) * @see org.spdx.spdxspreadsheet.AbstractSheet#verify() */ @Override public String verify() { try { if (sheet == null) { return "Worksheet for SPDX Snippets does not exist"; } Row firstRow = sheet.getRow(firstRowNum); for (int i = 0; i < NUM_COLS - 1; i++) { // Don't check the last (user defined) column Cell cell = firstRow.getCell(i + firstCellNum); if (cell == null || cell.getStringCellValue() == null || !cell.getStringCellValue().equals(HEADER_TITLES[i])) { return "Column " + HEADER_TITLES[i] + " missing for SPDX Snippet worksheet"; } } // validate rows boolean done = false; int rowNum = getFirstDataRow(); while (!done) { Row row = sheet.getRow(rowNum); if (row == null || row.getCell(firstCellNum) == null) { done = true; } else { String error = validateRow(row); if (error != null) { return error; } rowNum++; } } return null; } catch (Exception ex) { return "Error in verifying SPDX Snippet work sheet: " + ex.getMessage(); } } /** * @param row * @return */ private String validateRow(Row row) { for (int i = 0; i < NUM_COLS; i++) { Cell cell = row.getCell(i); if (cell == null) { if (REQUIRED[i]) { return "Required cell " + HEADER_TITLES[i] + " missing for row " + String.valueOf(row.getRowNum()); } } else { if (i == CONCLUDED_LICENSE_COL) { try { LicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue(), null); } catch (SpreadsheetException ex) { return "Invalid asserted license string in row " + String.valueOf(row.getRowNum()) + " details: " + ex.getMessage(); } } else if (i == BYTE_RANGE_COL || i == LINE_RANGE_COL) { String range = cell.getStringCellValue(); if (range != null && !range.isEmpty()) { Matcher rangeMatcher = NUMBER_RANGE_PATTERN.matcher(cell.getStringCellValue()); if (!rangeMatcher.matches()) { return "Invalid range for " + HEADER_TITLES[i] + ": " + cell.getStringCellValue(); } int start = 0; int end = 0; try { start = Integer.parseInt(rangeMatcher.group(1)); end = Integer.parseInt(rangeMatcher.group(2)); if (start >= end) { return "Invalid range for " + HEADER_TITLES[i] + ": " + cell.getStringCellValue() + ". End is not greater than or equal to the end."; } } catch (Exception ex) { return "Invalid range for " + HEADER_TITLES[i] + ": " + cell.getStringCellValue(); } } } } } return null; } public static void create(Workbook wb, String sheetName) { int sheetNum = wb.getSheetIndex(sheetName); if (sheetNum >= 0) { wb.removeSheetAt(sheetNum); } Sheet sheet = wb.createSheet(sheetName); CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); CellStyle centerStyle = AbstractSheet.createCenterStyle(wb); CellStyle wrapStyle = AbstractSheet.createLeftWrapStyle(wb); Row row = sheet.createRow(0); for (int i = 0; i < HEADER_TITLES.length; i++) { sheet.setColumnWidth(i, COLUMN_WIDTHS[i] * 256); if (LEFT_WRAP[i]) { sheet.setDefaultColumnStyle(i, wrapStyle); } else if (CENTER_NOWRAP[i]) { sheet.setDefaultColumnStyle(i, centerStyle); } Cell cell = row.createCell(i); cell.setCellStyle(headerStyle); cell.setCellValue(HEADER_TITLES[i]); } } /** * @param snippet * @throws SpreadsheetException */ public void add(SpdxSnippet snippet) throws SpreadsheetException { Row row = addRow(); if (snippet.getId() != null && !snippet.getId().isEmpty()) { row.createCell(ID_COL).setCellValue(snippet.getId()); } if (snippet.getName() != null && !snippet.getName().isEmpty()) { row.createCell(NAME_COL).setCellValue(snippet.getName()); } SpdxFile snippetFromFile; try { snippetFromFile = snippet.getSnippetFromFile(); } catch (InvalidSPDXAnalysisException e) { logger.error("Error getting the snippetFromFile", e); throw new SpreadsheetException( "Unable to get the Snippet from File from the Snippet: " + e.getMessage()); } if (snippetFromFile != null && snippetFromFile.getId() != null) { row.createCell(SNIPPET_FROM_FILE_ID_COL).setCellValue(snippetFromFile.getId()); } StartEndPointer byteRange; try { byteRange = snippet.getByteRange(); } catch (InvalidSPDXAnalysisException e) { logger.error("Error getting the byteRange", e); throw new SpreadsheetException("Unable to get the byte range from the Snippet: " + e.getMessage()); } if (byteRange != null) { try { row.createCell(BYTE_RANGE_COL).setCellValue(rangeToStr(byteRange)); } catch (InvalidSPDXAnalysisException e) { logger.error("Invalid byte range", e); throw new SpreadsheetException("Invalid byte range: " + e.getMessage()); } } StartEndPointer lineRange; try { lineRange = snippet.getLineRange(); } catch (InvalidSPDXAnalysisException e) { logger.error("Error getting the lineRange", e); throw new SpreadsheetException("Unable to get the line range from the Snippet: " + e.getMessage()); } if (lineRange != null) { try { row.createCell(LINE_RANGE_COL).setCellValue(rangeToStr(lineRange)); } catch (InvalidSPDXAnalysisException e) { logger.error("Invalid line range", e); throw new SpreadsheetException("Invalid line range: " + e.getMessage()); } } if (snippet.getLicenseConcluded() != null) { row.createCell(CONCLUDED_LICENSE_COL).setCellValue(snippet.getLicenseConcluded().toString()); } AnyLicenseInfo[] licenseInfoFromSnippet = snippet.getLicenseInfoFromFiles(); if (licenseInfoFromSnippet != null && licenseInfoFromSnippet.length > 0) { row.createCell(LICENSE_INFO_IN_SNIPPET_COL) .setCellValue(PackageInfoSheet.licensesToString(licenseInfoFromSnippet)); } if (snippet.getLicenseComments() != null) { row.createCell(LICENSE_COMMENT_COL).setCellValue(snippet.getLicenseComments()); } if (snippet.getCopyrightText() != null) { row.createCell(COPYRIGHT_COL).setCellValue(snippet.getCopyrightText()); } if (snippet.getComment() != null) { row.createCell(COMMENT_COL).setCellValue(snippet.getComment()); } this.snippetCache.put(snippet.getId(), snippet); } /** * @param byteRange * @return * @throws InvalidSPDXAnalysisException */ private String rangeToStr(StartEndPointer rangePointer) throws InvalidSPDXAnalysisException { SinglePointer startPointer = rangePointer.getStartPointer(); if (startPointer == null) { throw new InvalidSPDXAnalysisException("Missing start pointer"); } SinglePointer endPointer = rangePointer.getEndPointer(); if (endPointer == null) { throw new InvalidSPDXAnalysisException("Missing end pointer"); } String start = null; if (startPointer instanceof ByteOffsetPointer) { start = String.valueOf(((ByteOffsetPointer) startPointer).getOffset()); } else if (startPointer instanceof LineCharPointer) { start = String.valueOf(((LineCharPointer) startPointer).getLineNumber()); } else { logger.error("Unknown pointer type for start pointer " + startPointer.toString()); throw new InvalidSPDXAnalysisException("Unknown pointer type for start pointer"); } String end = null; if (endPointer instanceof ByteOffsetPointer) { end = String.valueOf(((ByteOffsetPointer) endPointer).getOffset()); } else if (endPointer instanceof LineCharPointer) { end = String.valueOf(((LineCharPointer) endPointer).getLineNumber()); } else { logger.error("Unknown pointer type for start pointer " + startPointer.toString()); throw new InvalidSPDXAnalysisException("Unknown pointer type for start pointer"); } return start + ":" + end; } /** * Get the SPDX snippet represented in the row rownum. * IMPORTANT: The Snippet From File will only be filled in if the associated file is found in the container. * This property can be set after calling getSnippet if the model is not already populated with the file * The ID from the Snippet From File can be obtained through the <code> getSnippetFileId(int rowNum)</code> method * @param rowNum * @return Snippet at the row rowNum or null if the row does not exist * @throws SpreadsheetException */ public SpdxSnippet getSnippet(int rowNum, SpdxDocumentContainer container) throws SpreadsheetException { if (sheet == null) { return null; } Row row = sheet.getRow(rowNum); if (row == null) { return null; } String ver = validateRow(row); if (ver != null && !ver.isEmpty()) { throw (new SpreadsheetException(ver)); } String id = null; if (row.getCell(ID_COL) != null) { id = row.getCell(ID_COL).getStringCellValue(); } if (this.snippetCache.containsKey(id)) { return this.snippetCache.get(id); } String name = null; if (row.getCell(NAME_COL) != null) { name = row.getCell(NAME_COL).getStringCellValue(); } StartEndPointer byteRange = null; if (row.getCell(BYTE_RANGE_COL) != null) { String range = row.getCell(BYTE_RANGE_COL).getStringCellValue(); if (range != null && !range.isEmpty()) { int start = 0; int end = 0; Matcher rangeMatcher = NUMBER_RANGE_PATTERN.matcher(range); if (!rangeMatcher.matches()) { throw new SpreadsheetException("Invalid byte range: " + range); } try { start = Integer.parseInt(rangeMatcher.group(1)); end = Integer.parseInt(rangeMatcher.group(2)); } catch (Exception ex) { throw new SpreadsheetException("Invalid byte range: " + range); } // Note: the reference should be filled in when the snippetFromFile is set for the Spdx Snippet ByteOffsetPointer startPointer = new ByteOffsetPointer(null, start); ByteOffsetPointer endPointer = new ByteOffsetPointer(null, end); byteRange = new StartEndPointer(startPointer, endPointer); } } StartEndPointer lineRange = null; if (row.getCell(LINE_RANGE_COL) != null) { String range = row.getCell(LINE_RANGE_COL).getStringCellValue(); if (range != null && !range.isEmpty()) { int start = 0; int end = 0; Matcher rangeMatcher = NUMBER_RANGE_PATTERN.matcher(range); if (!rangeMatcher.matches()) { throw new SpreadsheetException("Invalid line range: " + range); } try { start = Integer.valueOf(rangeMatcher.group(1)); end = Integer.valueOf(rangeMatcher.group(2)); } catch (Exception ex) { throw new SpreadsheetException("Invalid line range: " + range); } // Note: the reference should be filled in when the snippetFromFile is set for the Spdx Snippet LineCharPointer startPointer = new LineCharPointer(null, start); LineCharPointer endPointer = new LineCharPointer(null, end); lineRange = new StartEndPointer(startPointer, endPointer); } } AnyLicenseInfo concludedLicense = null; Cell concludedLicenseCell = row.getCell(CONCLUDED_LICENSE_COL); if (concludedLicenseCell != null && !concludedLicenseCell.getStringCellValue().isEmpty()) { concludedLicense = LicenseInfoFactory.parseSPDXLicenseString(concludedLicenseCell.getStringCellValue(), container); } else { concludedLicense = null; } AnyLicenseInfo[] seenLicenses = new AnyLicenseInfo[0]; Cell seenLicenseCell = row.getCell(LICENSE_INFO_IN_SNIPPET_COL); if (seenLicenseCell != null && !seenLicenseCell.getStringCellValue().isEmpty()) { String[] licenseStrings = seenLicenseCell.getStringCellValue().split(","); seenLicenses = new AnyLicenseInfo[licenseStrings.length]; for (int i = 0; i < licenseStrings.length; i++) { seenLicenses[i] = LicenseInfoFactory.parseSPDXLicenseString(licenseStrings[i].trim(), container); } } else { seenLicenses = null; } String licenseComments = null; Cell licCommentCell = row.getCell(LICENSE_COMMENT_COL); if (licCommentCell != null) { licenseComments = licCommentCell.getStringCellValue(); } else { licenseComments = ""; } String copyright; Cell copyrightCell = row.getCell(COPYRIGHT_COL); if (copyrightCell != null) { copyright = copyrightCell.getStringCellValue(); } else { copyright = ""; } String comment = null; Cell commentCell = row.getCell(COMMENT_COL); if (commentCell != null) { comment = commentCell.getStringCellValue(); } String snippetFromFileId = getSnippetFileId(rowNum); SpdxFile snippetFromFile = null; if (snippetFromFileId != null && !snippetFromFileId.isEmpty()) { SpdxElement fromFileElement; try { fromFileElement = container.findElementById(snippetFromFileId); if (fromFileElement instanceof SpdxFile) { snippetFromFile = (SpdxFile) fromFileElement; // Fix up the ranges to reference this snippetFromFile if (byteRange != null) { byteRange.getStartPointer().setReference(snippetFromFile); byteRange.getEndPointer().setReference(snippetFromFile); } if (lineRange != null) { lineRange.getStartPointer().setReference(snippetFromFile); lineRange.getEndPointer().setReference(snippetFromFile); } } else { logger.warn( "Element associated with the snippetFromFile is not of type SPDX File. Null will be used"); } } catch (InvalidSPDXAnalysisException e) { logger.warn("Error getting snipet from file by ID. snippetFromFile will be set to null"); } } SpdxSnippet retval = new SpdxSnippet(name, comment, new Annotation[0], new Relationship[0], concludedLicense, seenLicenses, copyright, licenseComments, snippetFromFile, byteRange, lineRange); try { retval.setId(id); } catch (InvalidSPDXAnalysisException e) { logger.error("Error setting ID for SpdxSnippet", e); throw new SpreadsheetException("Error setting ID for SpdxSnippet: " + e.getMessage()); } this.snippetCache.put(id, retval); return retval; } /** * Get the SpdxFromFileSNippet for the given row * @param rowNum * @return * @throws SpreadsheetException */ public String getSnippetFileId(int rowNum) throws SpreadsheetException { Row row = sheet.getRow(rowNum); if (row == null) { return null; } String ver = validateRow(row); if (ver != null && !ver.isEmpty()) { throw (new SpreadsheetException(ver)); } String id = null; if (row.getCell(SNIPPET_FROM_FILE_ID_COL) != null) { id = row.getCell(SNIPPET_FROM_FILE_ID_COL).getStringCellValue(); } return id; } }