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}