001/*
002 * Copyright 2015-2024 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.io.OutputStream;
017import java.util.Arrays;
018
019import org.minidns.record.Record.TYPE;
020
021/**
022 * Generic payload class.
023 */
024public abstract class Data {
025
026    /**
027     * The payload type.
028     * @return The payload type.
029     */
030    public abstract TYPE getType();
031
032    /**
033     * The internal method used to serialize Data subclasses.
034     *
035     * @param dos the output stream to serialize to.
036     * @throws IOException if an I/O error occurs.
037     */
038    protected abstract void serialize(DataOutputStream dos) throws IOException;
039
040    private byte[] bytes;
041
042    private void setBytes() {
043        if (bytes != null) return;
044
045        ByteArrayOutputStream baos = new ByteArrayOutputStream();
046        DataOutputStream dos = new DataOutputStream(baos);
047        try {
048            serialize(dos);
049        } catch (IOException e) {
050            // Should never happen.
051            throw new AssertionError(e);
052        }
053        bytes = baos.toByteArray();
054    }
055
056    public final int length() {
057        setBytes();
058        return bytes.length;
059    }
060
061    public final void toOutputStream(OutputStream outputStream) throws IOException {
062        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
063        toOutputStream(dataOutputStream);
064    }
065
066    /**
067     * Write the binary representation of this payload to the given {@link DataOutputStream}.
068     *
069     * @param dos the DataOutputStream to write to.
070     * @throws IOException if an I/O error occurs.
071     */
072    public final void toOutputStream(DataOutputStream dos) throws IOException {
073        setBytes();
074        dos.write(bytes);
075    }
076
077    public final byte[] toByteArray() {
078        setBytes();
079        return bytes.clone();
080    }
081
082    private transient Integer hashCodeCache;
083
084    @Override
085    public final int hashCode() {
086        if (hashCodeCache == null) {
087            setBytes();
088            hashCodeCache = Arrays.hashCode(bytes);
089        }
090        return hashCodeCache;
091    }
092
093    @Override
094    public final boolean equals(Object other) {
095        if (!(other instanceof Data)) {
096            return false;
097        }
098        if (other == this) {
099            return true;
100        }
101        Data otherData = (Data) other;
102        otherData.setBytes();
103        setBytes();
104
105        return Arrays.equals(bytes, otherData.bytes);
106    }
107}