gobblin.util.guid.Guid.java Source code

Java tutorial

Introduction

Here is the source code for gobblin.util.guid.Guid.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package gobblin.util.guid;

import lombok.EqualsAndHashCode;

import java.io.IOException;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;

import com.google.common.base.Charsets;

/**
 * Class wrapping a byte array representing a guid. A {@link Guid} is intended to uniquely identify objects in a
 * replicable way.
 */
@EqualsAndHashCode
public class Guid {

    public static final int GUID_LENGTH = 20;

    final byte[] sha;

    /**
     * Creates a {@link Guid} by computing the sha of the input bytes.
     */
    public Guid(byte[] bytes) {
        this(bytes, false);
    }

    /**
     * @param bytes byte array.
     * @param isSha true if bytes are already a sha.
     */
    private Guid(byte[] bytes, boolean isSha) {
        if (isSha) {
            this.sha = bytes;
        } else {
            this.sha = computeGuid(bytes);
        }
    }

    /**
     * Generate a {@link Guid} for an array of {@link HasGuid}.
     * @param objs array of {@link HasGuid}.
     * @return a single {@link Guid} for the array.
     * @throws IOException
     */
    public static Guid fromHasGuid(HasGuid... objs) throws IOException {
        byte[][] byteArrays = new byte[objs.length][];
        for (int i = 0; i < objs.length; i++) {
            byteArrays[i] = objs[i].guid().sha;
        }
        return fromByteArrays(byteArrays);
    }

    /**
     * Generate a {@link Guid} for an array of Strings.
     * @param strings array of Strings.
     * @return a single {@link Guid} for the array.
     * @throws IOException
     */
    public static Guid fromStrings(String... strings) throws IOException {

        if (strings == null || strings.length == 0) {
            throw new IOException("Attempting to compute guid for an empty array.");
        }

        return new Guid(StringUtils.join(strings).getBytes(Charsets.UTF_8));
    }

    /**
     * Generate a {@link Guid} for an array of byte arrays.
     * @param byteArrays array of byte arrays.
     * @return a single {@link Guid} for the array.
     * @throws IOException
     */
    public static Guid fromByteArrays(byte[]... byteArrays) throws IOException {
        if (byteArrays == null || byteArrays.length == 0) {
            throw new IOException("Attempting to compute guid for an empty array.");
        }

        if (byteArrays.length == 1) {
            return new Guid(byteArrays[0]);
        }
        byte[] tmp = new byte[0];
        for (byte[] arr : byteArrays) {
            tmp = ArrayUtils.addAll(tmp, arr);
        }
        return new Guid(tmp);
    }

    /**
     * Reverse of {@link #toString}. Deserializes a {@link Guid} from a previously serialized one.
     * @param str Serialized {@link Guid}.
     * @return deserialized {@link Guid}.
     * @throws IOException
     */
    public static Guid deserialize(String str) throws IOException {
        if (str.length() != 2 * GUID_LENGTH) {
            throw new IOException("String is not an encoded guid.");
        }
        try {
            return new Guid(Hex.decodeHex(str.toCharArray()), true);
        } catch (DecoderException de) {
            throw new IOException(de);
        }
    }

    /**
     * Combine multiple {@link Guid}s into a single {@link Guid}.
     * @throws IOException
     */
    public static Guid combine(Guid... guids) throws IOException {
        byte[][] byteArrays = new byte[guids.length][];
        for (int i = 0; i < guids.length; i++) {
            byteArrays[i] = guids[i].sha;
        }
        return fromByteArrays(byteArrays);
    }

    /**
     * Creates a new {@link Guid} which is a unique, replicable representation of the pair (this, byteArrays).
     * @param byteArrays an array of byte arrays.
     * @return a new {@link Guid}.
     * @throws IOException
     */
    public Guid append(byte[]... byteArrays) throws IOException {
        if (byteArrays == null || byteArrays.length == 0) {
            return this;
        }
        return fromByteArrays(ArrayUtils.add(byteArrays, this.sha));
    }

    /**
     * Creates a new {@link Guid} which is a unique, replicable representation of the pair (this, guids). Equivalent to
     * combine(this, guid1, guid2, ...)
     * @param guids an array of {@link Guid}.
     * @return a new {@link Guid}.
     * @throws IOException
     */
    public Guid append(Guid... guids) throws IOException {
        if (guids == null || guids.length == 0) {
            return this;
        }
        return combine(ArrayUtils.add(guids, this));
    }

    /**
     * Creates a new {@link Guid} which is a unique, replicable representation of the pair (this, objs).
     * @param objs an array of {@link HasGuid}.
     * @return a new {@link Guid}.
     * @throws IOException
     */
    public Guid append(HasGuid... objs) throws IOException {
        if (objs == null || objs.length == 0) {
            return this;
        }
        return fromHasGuid(ArrayUtils.add(objs, new SimpleHasGuid(this)));
    }

    /**
     * Serializes the guid into a hex string. The original {@link Guid} can be recovered using {@link #deserialize}.
     */
    @Override
    public String toString() {
        return Hex.encodeHexString(this.sha);
    }

    // DigestUtils.sha is deprecated for sha1, but sha1 is not available in old versions of commons codec
    @SuppressWarnings("deprecation")
    private static byte[] computeGuid(byte[] bytes) {
        return DigestUtils.sha(bytes);
    }

    static class SimpleHasGuid implements HasGuid {
        private final Guid guid;

        public SimpleHasGuid(Guid guid) {
            this.guid = guid;
        }

        @Override
        public Guid guid() throws IOException {
            return this.guid;
        }
    }

}