package net.decix.jipfix.header; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import net.decix.util.HeaderBytesException; import net.decix.util.HeaderParseException; import net.decix.util.Utility; /** * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Set ID | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * @author tking * */ public class SetHeader extends AbstractHeader implements IPFIXEntity { private final static Logger LOGGER = Logger.getLogger(SetHeader.class.getName()); private final static int HEADERLENGTH = 4; private int setID; private List<DataRecord> dataRecords = new ArrayList<DataRecord>(); private List<TemplateRecord> templateRecords = new ArrayList<TemplateRecord>(); private List<OptionTemplateRecord> optionTemplateRecords = new ArrayList<OptionTemplateRecord>(); /** * A value of 2 is reserved for Template Sets. A value of 3 is reserved * for Options Template Sets. Values from 4 to 255 are reserved for * future use. Values 256 and above are used for Data Sets. The Set ID * values of 0 and 1 are not used, for historical reasons. * * @return */ public int getSetID() { return setID; } public void setSetID(int setID) { this.setID = setID; } public List<DataRecord> getDataRecords() { return dataRecords; } public void setDataRecords(List<DataRecord> dataRecords) { this.dataRecords = dataRecords; updateLength(); } public List<TemplateRecord> getTemplateRecords() { return templateRecords; } public void setTemplateRecords(List<TemplateRecord> templateRecords) { this.templateRecords = templateRecords; updateLength(); } public List<OptionTemplateRecord> getOptionTemplateRecords() { return optionTemplateRecords; } public void setOptionTemplateRecords(List<OptionTemplateRecord> optionTemplateRecords) { this.optionTemplateRecords = optionTemplateRecords; updateLength(); } private void updateLength() { int newLength = HEADERLENGTH; for (TemplateRecord template : templateRecords) { newLength += template.getLength(); } for (OptionTemplateRecord optionTemplate : optionTemplateRecords) { newLength += optionTemplate.getLength(); } for (DataRecord record : dataRecords) { newLength += record.getLength(); } this.length = newLength; } public static SetHeader parse(byte[] data) throws HeaderParseException { try { if (data.length < 4) throw new HeaderParseException("Data array too short."); SetHeader sh = new SetHeader(); // set id byte[] setID = new byte[2]; System.arraycopy(data, 0, setID, 0, 2); sh.setSetID(Utility.twoBytesToInteger(setID)); // length byte[] length = new byte[2]; System.arraycopy(data, 2, length, 0, 2); sh.setLength(Utility.twoBytesToInteger(length)); // 2 -> template sets; if (sh.getSetID() == 2) { int offset = 4; byte[] subData = new byte[sh.getLength() - offset]; System.arraycopy(data, offset, subData, 0, subData.length); TemplateRecord tr = TemplateRecord.parse(subData); sh.getTemplateRecords().add(tr); } // 3 -> template option sets else if (sh.getSetID() == 3) { int offset = 4; byte[] subData = new byte[sh.getLength() - offset]; System.arraycopy(data, offset, subData, 0, subData.length); OptionTemplateRecord otr = OptionTemplateRecord.parse(subData); sh.getOptionTemplateRecords().add(otr); } // > 256 -> data record; else if (sh.getSetID() == 256) { int offset = 4; byte[] subData = new byte[sh.getLength() - offset]; System.arraycopy(data, offset, subData, 0, SamplingDataRecord.LENGTH); SamplingDataRecord sdr = SamplingDataRecord.parse(subData); sh.getDataRecords().add(sdr); } else if (sh.getSetID() == 306) { int offset = 4; while ((sh.getLength() - offset - L2IPDataRecord.LENGTH) >= 0) { byte[] subData = new byte[sh.getLength() - offset]; System.arraycopy(data, offset, subData, 0, L2IPDataRecord.LENGTH); L2IPDataRecord lidr = L2IPDataRecord.parse(subData); sh.getDataRecords().add(lidr); offset += L2IPDataRecord.LENGTH; } if ((sh.getLength() - offset) != 0) LOGGER.log(Level.INFO, "Unused bytes: " + (sh.getLength() - offset)); } else { LOGGER.log(Level.INFO, "Set ID " + sh.getSetID() + " is unknown and not handled"); } return sh; } catch (Exception e) { throw new HeaderParseException("Parse error: " + e.getMessage()); } } public byte[] getBytes() throws HeaderBytesException { try { int length = HEADERLENGTH; for (DataRecord dr : dataRecords) { length += dr.getLength(); } for (TemplateRecord tr : templateRecords) { length += tr.getLength(); } for (OptionTemplateRecord otr : optionTemplateRecords) { length += otr.getLength(); } byte[] data = new byte[length]; // set id System.arraycopy(Utility.integerToTwoBytes(getSetID()), 0, data, 0, 2); // length System.arraycopy(Utility.integerToTwoBytes(getLength()), 0, data, 2, 2); // data record int offset = 4; for (DataRecord record : dataRecords) { System.arraycopy(record.getBytes(), 0, data, offset, record.getLength()); offset += record.getLength(); } for (TemplateRecord record : templateRecords) { byte[] recordData = record.getBytes(); System.arraycopy(recordData, 0, data, offset, record.getLength()); offset += recordData.length; } for (OptionTemplateRecord record : optionTemplateRecords) { byte[] recordData = record.getBytes(); System.arraycopy(recordData, 0, data, offset, record.getLength()); offset += recordData.length; } return data; } catch (Exception e) { throw new HeaderBytesException("Error while generating the bytes: " + e.getMessage()); } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[SetHeader]: "); sb.append("Set ID: "); sb.append(setID); sb.append(", Length: "); sb.append(length); sb.append(", Data records: "); sb.append(dataRecords.size()); sb.append(", "); for (DataRecord record : dataRecords) { sb.append(record); sb.append(", "); } sb.append("Template records: "); sb.append(templateRecords.size()); sb.append(", "); for (TemplateRecord record : templateRecords) { sb.append(record); sb.append(", "); } sb.append("Option template records: "); sb.append(optionTemplateRecords.size()); sb.append(", "); for (OptionTemplateRecord record : optionTemplateRecords) { sb.append(record); sb.append(", "); } return sb.toString(); } }