Java tutorial
/* * Copyright 2011-2018 B2i Healthcare Pte Ltd, http://b2i.sg * * 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 com.b2international.snowowl.datastore.server.importer; import java.text.MessageFormat; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; import org.apache.poi.ss.usermodel.Row; import com.b2international.commons.StringUtils; import com.b2international.snowowl.datastore.importer.TerminologyImportType; import com.b2international.snowowl.datastore.importer.TerminologyImportValidationDefect; import com.b2international.snowowl.datastore.importer.TerminologyImportValidationDefect.DefectType; import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; /** * Abstract validator class for terminology sheet validation during the import. * * @since Snow Owl 3.0.1 * * @param <T> * the terminology for the validation process. */ public abstract class AbstractTerminologyImportValidator<T> { private final TerminologyImportType importType; private final TerminologyImportExcelParser excelParser; private final Map<String, TerminologyImportValidationDefect> defects = Maps.newHashMap(); private final Map<String, T> databaseComponents; /** * Keys are the properties for instance, 'OID' or 'short name' * Values are the actual values for the properties such as '2.16.840.1.113883.6.96' or 'SNOMEDCT' * And the values for the multimap are the sheet names where the property with the actual value has occurred. */ private final Map<String, Multimap<String, String>> uniqueAttributes = Maps.newHashMap(); public AbstractTerminologyImportValidator(final TerminologyImportType importType, final TerminologyImportExcelParser excelParser, final Map<String, T> databaseComponents) { this.importType = importType; this.excelParser = excelParser; this.databaseComponents = databaseComponents; } /** * Validates the sheets from the imported excel file. * * @return a collection of the validation defects. */ public Collection<TerminologyImportValidationDefect> validate() { for (final String sheetName : excelParser.getProperties().keySet()) { validateProperties(sheetName, excelParser.getProperties().get(sheetName)); validateMetadata(sheetName, excelParser.getMetadata().get(sheetName)); validateMembers(sheetName, excelParser.getMembers().get(sheetName)); } checkDuplication(); return getDefects(); } /** * Validates the properties from the sheet. * * @param sheetName * the name of the sheet. * @param properties * the properties from the sheet. */ protected abstract void validateProperties(final String sheetName, final List<String> properties); /** * Validates the members from the sheet. * * @param sheetName * the name of the sheet. * @param members * the members from the sheet. */ protected abstract void validateMembers(final String sheetName, final Set<Row> members); /** * Returns true if rows contain duplicate values in the given column. * * @param the name of the sheet being validated * @param rows to check for duplicates * @param uniqueColumn the index of the unique value column * @return true if duplicates found */ protected void validateDuplicateFields(final String sheetName, final Set<Row> rows, final int uniqueColumn) { Set<String> fieldSet = rows.stream() .map(row -> ExcelUtilities.extractContentAsString(row.getCell(uniqueColumn))) .collect(Collectors.<String>toSet()); if (rows.size() > fieldSet.size()) { addDefect(sheetName, DefectType.DUPLICATE, String.format("Spreadsheet %s, has duplicated fields in column %s.", sheetName, uniqueColumn)); } } /** * Validates the metadata from the sheet. * * @param sheetName * the name of the sheet. * @param metadata * the metadata to validate. */ protected void validateMetadata(final String sheetName, final Multimap<String, String> metadata) { for (final Entry<String, Collection<String>> entry : metadata.asMap().entrySet()) { final String displayName = entry.getKey(); final Set<String> keywords = Sets.newHashSet(); for (final String keyword : entry.getValue()) { validateNonEmptyAttribute(sheetName, keyword, MessageFormat.format("Keyword is empty in ''{0}'' group", displayName)); if (!keywords.add(keyword)) { addDefect(sheetName, DefectType.GROUP, MessageFormat .format("''{0}'' keyword is duplicated in group ''{1}''.", keyword, displayName)); } } } } /** * Validates the given attribute against emptiness. * * @param sheetName * the name of the sheet. * @param attribute * the attribute to be validated. * @param errorMessage * the error message if the attribute is empty. */ protected void validateNonEmptyAttribute(final String sheetName, final String attribute, final String errorMessage) { if (StringUtils.isEmpty(attribute)) { addDefect(sheetName, DefectType.EMPTINESS, errorMessage); } } /** * Validates if the given value is numeric or not. * * @param sheetName * the name of the sheet. * @param attribute * the numeric attribute to validate. * @param errorMessage * the error message if the attribute is not valid. */ protected void validateNumberFormat(final String sheetName, final String attribute, final String errorMessage) { if (!StringUtils.isEmpty(attribute)) { if (!attribute.matches("\\d*\\.?\\d*")) { addDefect(sheetName, DefectType.INCORRECT_FORMAT, errorMessage); } } } /** * Validates if the value from the sheet and database are equal or not. * * @param sheetName * the name of the sheet. * @param sheetValue * the value from the sheet. * @param databaseValue * the value from the database. * @param errorMessage * the error message if the attributes are not equal. */ protected void validateMatchingAttribute(final String sheetName, final String sheetValue, final String databaseValue, final String errorMessage) { if (!sheetValue.equals(databaseValue)) { addDefect(sheetName, DefectType.DIFFERENCES, errorMessage); } } /** * Adds a new defect to the defects map. * * @param sheetName * the name of the sheet. * @param defectType * the type of the defect. * @param errorMessage * the error message for the defect. */ protected void addDefect(final String sheetName, final DefectType defectType, final String errorMessage) { if (null == defects.get(sheetName)) { final TerminologyImportValidationDefect defect = new TerminologyImportValidationDefect(sheetName); defect.addDefect(defectType, errorMessage); defects.put(sheetName, defect); } else { defects.get(sheetName).addDefect(defectType, errorMessage); } } protected void addUniqueAttribute(final String attributeName, final String attributeValue, final String sheetName) { Multimap<String, String> attribuetValueSheetMultimap = uniqueAttributes.get(attributeName); if (null == attribuetValueSheetMultimap) { attribuetValueSheetMultimap = HashMultimap.create(); } attribuetValueSheetMultimap.put(attributeValue, sheetName); uniqueAttributes.put(attributeName, attribuetValueSheetMultimap); } public boolean isClearImport() { return importType == TerminologyImportType.CLEAR; } public boolean isMergeImport() { return importType == TerminologyImportType.MERGE; } public boolean isReplaceImport() { return importType == TerminologyImportType.REPLACE; } public Collection<TerminologyImportValidationDefect> getDefects() { return defects.values(); } public TerminologyImportExcelParser getExcelParser() { return excelParser; } public Map<String, T> getDatabaseComponents() { return databaseComponents; } private void checkDuplication() { for (final String attributeName : uniqueAttributes.keySet()) { final Multimap<String, String> attributeValueSheetNamesMap = uniqueAttributes.get(attributeName); for (final String attributeValue : attributeValueSheetNamesMap.keySet()) { final Collection<String> sheetNames = attributeValueSheetNamesMap.get(attributeValue); if (sheetNames.size() > 1) { for (final String sheetName : sheetNames) { addDefect(sheetName, DefectType.DIFFERENCES, "'" + attributeName + "' attribute must be unique."); } } } } } }