com.linkedin.databus.client.registration.RegistrationIdGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.linkedin.databus.client.registration.RegistrationIdGenerator.java

Source

package com.linkedin.databus.client.registration;
/*
 *
 * Copyright 2013 LinkedIn Corp. All rights reserved
 *
 * Licensed 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.
 *
*/

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger;

import com.linkedin.databus.client.pub.RegistrationId;
import com.linkedin.databus.core.data_model.DatabusSubscription;

public class RegistrationIdGenerator {
    public static final Logger LOG = Logger.getLogger(RegistrationIdGenerator.class);

    /**
     * Database of Ids for registrations created so far
     */
    private static Set<String> _registrationIdDatabase;
    static {
        _registrationIdDatabase = new HashSet<String>();
    }

    /**
     * Queries the existing database of registrations inside the client and generates a new id different from
     * any of them
     *
     * @param prefix : A String prefix which can be specified to precede the id to be generated. Typically this
     *                 is the name of the Consumer class
     * @param subsSources : List of subscriptions the consumer is interested in
     * @return RegistrationId : Generated based on the prefix _ 8 byte md5 hash ( subscriptions ) _ count
     */
    public static RegistrationId generateNewId(String prefix, Collection<DatabusSubscription> subsSources) {
        StringBuilder subscription = new StringBuilder();
        for (DatabusSubscription ds : subsSources) {
            if (ds != null)
                subscription.append(ds.generateSubscriptionString());
        }

        String id = generateUniqueString(prefix, subscription.toString());
        RegistrationId rid = new RegistrationId(id);
        return rid;
    }

    /**
     * For a given regId , this API queries the existing database of registrations inside the client.
     * If the id is available, it is returned as a registration id, otherwise a running counter 
     * is appended to the suggested regId.
     * 
     * @param id : A suggested name by the caller to be used as regId. If the id is not available, a running counter
     *             is appended 
     * @return RegistrationId : Generated based on the id _count
     */
    public static RegistrationId generateNewId(String id) {
        String r = generateUniqueString(id);
        RegistrationId rid = new RegistrationId(r);
        return rid;
    }

    /**
     * Checks if the input rid can be used as a RegistrationId.
     * Specifically, checks to see if the underlying id is already in use
     * @return
     */
    public static boolean isIdValid(RegistrationId rid) {
        String id = rid.getId();
        synchronized (RegistrationIdGenerator.class) {
            if (_registrationIdDatabase.contains(id)) {
                return false;
            } else {
                return true;
            }
        }
    }

    /**
     * Adds an id into the RegistrationId database.
     * This is useful for unit-testing / inserting an id out-of-band into the database, so that such an id
     * would not get generated again
     *
     * @param id
     */
    public static void insertId(RegistrationId rid) {
        String id = rid.getId();
        synchronized (RegistrationIdGenerator.class) {
            _registrationIdDatabase.add(id);
        }
    }

    /**
     * Creates a unique string given a prefix ( which must appear as is ), a subscription string ( which is converted
     * to an 8 byte string ) and a count if there are duplicates with the previous two
     */
    private static String generateUniqueString(String prefix, String subscription) {
        final String delimiter = "_";
        String baseId = prefix + delimiter + generateByteHash(subscription);

        return generateUniqueString(baseId);
    }

    /**
     * Creates a unique registration Id string given an id. 
     * A running counter is appended if there are duplicates 
     */
    private static String generateUniqueString(String id) {
        final String delimiter = "_";
        String baseId = id;

        boolean success = false;
        boolean debugEnabled = LOG.isDebugEnabled();
        synchronized (RegistrationIdGenerator.class) {
            int count = _registrationIdDatabase.size();
            while (!success) {
                if (_registrationIdDatabase.contains(id)) {
                    if (debugEnabled)
                        LOG.debug("The generated id " + id + " already exists. Retrying ...");
                    id = baseId + delimiter + count;
                    count++;
                } else {
                    if (debugEnabled)
                        LOG.debug("Obtained a new ID " + id);
                    _registrationIdDatabase.add(id);
                    success = true;
                }
            }
        }
        return id;
    }

    /**
     * Generate a hash out of the String id
     *
     * @param id
     * @return
     */
    private static String generateByteHash(String id) {
        try {
            final MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(id.getBytes(Charset.forName("UTF8")));
            final byte[] resultsByte = messageDigest.digest();
            String hash = new String(Hex.encodeHex(resultsByte));

            final int length = 8;
            if (hash.length() > length)
                hash = hash.substring(0, length);

            return hash;
        } catch (NoSuchAlgorithmException nse) {
            LOG.error("Unexpected error : Got NoSuchAlgorithm exception for MD5");
            return "";
        }
    }

}