package com.threatconnect.sdk.parser.util.attribute; import com.opencsv.CSVReader; import com.threatconnect.sdk.parser.model.Group; import com.threatconnect.sdk.parser.model.GroupType; import com.threatconnect.sdk.parser.model.Indicator; import com.threatconnect.sdk.parser.model.Item; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; public class AttributeDefinitionUtil { public static final String ATTRIBUTES_FILE = "attributes.csv"; public static final String TYPE_DELIMITER = "|"; public static final int COLUMNS = 5; private static final Logger logger = LoggerFactory.getLogger(AttributeDefinitionUtil.class); private static AttributeDefinitionUtil instance; // holds the map of attributes private final Map<String, AttributeDefinition> attributeDefinitions; private AttributeDefinitionUtil() { this.attributeDefinitions = new HashMap<String, AttributeDefinition>(); loadAttributesCSV(); } private void loadAttributesCSV() { // holds the readers for the input stream InputStream inputStream = null; InputStreamReader isr = null; CSVReader reader = null; try { // load the csv file inputStream = findAttributesFile(); // check to see if the input stream is not null if (null != inputStream) { logger.info("Loading {}", ATTRIBUTES_FILE); // load the file into reader objects isr = new InputStreamReader(inputStream); reader = new CSVReader(isr); String[] nextLine; while ((nextLine = reader.readNext()) != null) { // make sure that there are exactly 5 parts if (nextLine.length != COLUMNS) { final String message = "Expected " + COLUMNS + " columns, found " + nextLine.length + " - " + Arrays.toString(nextLine); throw new InvalidAttributeDefinitionFileException(message); } else { // validate that no field is missing or empty for (int i = 0; i < COLUMNS; i++) { if (null == nextLine[i] || nextLine[i].trim().isEmpty()) { throw new InvalidAttributeDefinitionFileException( "Expected column is either missing or empty - " + Arrays.toString(nextLine)); } } // create the attribute object AttributeDefinition attributeDefinition = new AttributeDefinition(); attributeDefinition.setName(nextLine[0]); attributeDefinition.setDescription(nextLine[1]); attributeDefinition.setErrorMessage(nextLine[2]); try { attributeDefinition.setMaxSize(Integer.parseInt(nextLine[3].trim())); setTypes(attributeDefinition, nextLine[4]); // for each of the group types for (GroupType groupType : attributeDefinition.getGroupTypes()) { // add an entry for this attribute and type combination final String key = getKey(attributeDefinition.getName(), groupType); attributeDefinitions.put(key, attributeDefinition); logger.debug("Loaded attribute definition for {} - {}", attributeDefinition.getName(), groupType); } // for each of the indicator types for (String indicatorType : attributeDefinition.getIndicatorTypes()) { // add an entry for this attribute and type combination final String key = getKey(attributeDefinition.getName(), indicatorType); attributeDefinitions.put(key, attributeDefinition); logger.debug("Loaded attribute definition for {} - {}", attributeDefinition.getName(), indicatorType); } } catch (NumberFormatException e) { throw new InvalidAttributeDefinitionFileException("Invalid max size number. " + nextLine[3] + " is not a valid integer. - " + Arrays.toString(nextLine)); } catch (InvalidAttributeDefinitionTypesException e) { throw new InvalidAttributeDefinitionFileException( e.getMessage() + " - " + Arrays.toString(nextLine)); } } } } else { logger.info("No {} file was found.", ATTRIBUTES_FILE); } } catch (IOException e) { throw new InvalidAttributeDefinitionFileException(e); } finally { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(isr); IOUtils.closeQuietly(reader); } } private InputStream findAttributesFile() { try { return new FileInputStream(new File(ATTRIBUTES_FILE)); } catch (FileNotFoundException e) { return null; } } private void setTypes(final AttributeDefinition attributeDefinition, final String types) throws InvalidAttributeDefinitionTypesException { String[] typesArray = types.split(Pattern.quote(TYPE_DELIMITER)); // for each of the types for (String type : typesArray) { GroupType groupType; try { // attempt to load this group type groupType = GroupType.valueOf(type.trim().toUpperCase()); } catch (IllegalArgumentException e) { // its ok if it does not exist groupType = null; } // check to see if the group type is not null if (null != groupType) { attributeDefinition.getGroupTypes().add(groupType); } // this must be an indicator type (or custom indicator) else { String indicatorType = type.trim().toUpperCase(); attributeDefinition.getIndicatorTypes().add(indicatorType); } } } public boolean containsAttribute(final String attributeName, final Item item) { // check to see if this item is a group if (item instanceof Group) { Group group = (Group) item; return containsAttribute(attributeName, group.getGroupType()); } // check to see if this item is an indicator else if (item instanceof Indicator) { Indicator indicator = (Indicator) item; return containsAttribute(attributeName, indicator.getIndicatorType()); } // this should technically never happen unless a new item type is created else { return false; } } public boolean containsAttribute(final String attributeName, final String indicatorType) { return (null != getAttribute(attributeName, indicatorType)); } public boolean containsAttribute(final String attributeName, final GroupType groupType) { return (null != getAttribute(attributeName, groupType)); } public AttributeDefinition getAttribute(final String attributeName, final Item item) { // check to see if this item is a group if (item instanceof Group) { Group group = (Group) item; return getAttribute(attributeName, group.getGroupType()); } // check to see if this item is an indicator else if (item instanceof Indicator) { Indicator indicator = (Indicator) item; return getAttribute(attributeName, indicator.getIndicatorType()); } // this should technically never happen unless a new item type is created else { return null; } } public AttributeDefinition getAttribute(final String attributeName, final String indicatorType) { return attributeDefinitions.get(getKey(attributeName, indicatorType)); } public AttributeDefinition getAttribute(final String attributeName, final GroupType groupType) { return attributeDefinitions.get(getKey(attributeName, groupType)); } private String getKey(final String attributeName, final String indicatorType) { return attributeName + "|I|" + indicatorType.toString(); } private String getKey(final String attributeName, final GroupType groupType) { return attributeName + "|G|" + groupType.toString(); } public static synchronized AttributeDefinitionUtil getInstance() { // check to see if this instance is null if (null == instance) { instance = new AttributeDefinitionUtil(); } return instance; } }