001/* 002 * Copyright 2015-2018 the original author or authors 003 * 004 * This software is licensed under the Apache License, Version 2.0, 005 * the GNU Lesser General Public License version 2 or later ("LGPL") 006 * and the WTFPL. 007 * You may choose either license to govern your use of this software only 008 * upon the condition that you accept all of the terms of either 009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL. 010 */ 011package org.minidns.record; 012 013import java.io.ByteArrayOutputStream; 014import java.io.DataOutputStream; 015import java.io.IOException; 016import java.util.Arrays; 017 018import org.minidns.record.Record.TYPE; 019 020/** 021 * Generic payload class. 022 */ 023public abstract class Data { 024 025 Data() { 026 } 027 028 /** 029 * The payload type. 030 * @return The payload type. 031 */ 032 public abstract TYPE getType(); 033 034 /** 035 * The internal method used to serialize Data subclasses. 036 * 037 * @param dos the output stream to serialize to. 038 * @throws IOException if an I/O error occurs. 039 */ 040 protected abstract void serialize(DataOutputStream dos) throws IOException; 041 042 private byte[] bytes; 043 044 private final void setBytes() { 045 if (bytes != null) return; 046 047 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 048 DataOutputStream dos = new DataOutputStream(baos); 049 try { 050 serialize(dos); 051 } catch (IOException e) { 052 // Should never happen. 053 throw new AssertionError(e); 054 } 055 bytes = baos.toByteArray(); 056 } 057 058 public final int length() { 059 setBytes(); 060 return bytes.length; 061 } 062 063 /** 064 * Write the binary representation of this payload to the given {@link DataOutputStream}. 065 * 066 * @param dos the DataOutputStream to write to. 067 * @throws IOException if an I/O error occurs. 068 */ 069 public void toOutputStream(DataOutputStream dos) throws IOException { 070 setBytes(); 071 dos.write(bytes); 072 } 073 074 public final byte[] toByteArray() { 075 setBytes(); 076 return bytes.clone(); 077 } 078 079 private transient Integer hashCodeCache; 080 081 @Override 082 public final int hashCode() { 083 if (hashCodeCache == null) { 084 setBytes(); 085 hashCodeCache = bytes.hashCode(); 086 } 087 return hashCodeCache; 088 } 089 090 @Override 091 public final boolean equals(Object other) { 092 if (!(other instanceof Data)) { 093 return false; 094 } 095 if (other == this) { 096 return true; 097 } 098 Data otherData = (Data) other; 099 otherData.setBytes(); 100 setBytes(); 101 102 return Arrays.equals(bytes, otherData.bytes); 103 } 104}