com.torodb.mongodb.language.ObjectIdFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.torodb.mongodb.language.ObjectIdFactory.java

Source

/*
 * ToroDB
 * Copyright  2014 8Kdata Technology (www.8kdata.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package com.torodb.mongodb.language;

import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.primitives.UnsignedInteger;
import com.torodb.core.logging.DefaultLoggerFactory;
import com.torodb.mongowp.bson.BsonObjectId;
import com.torodb.mongowp.bson.impl.IntBasedBsonObjectId;
import org.apache.logging.log4j.Logger;

import java.lang.management.ManagementFactory;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.SecureRandom;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.concurrent.ThreadSafe;

@ThreadSafe
public class ObjectIdFactory {

    /*
     * TODO: The static part of this class should be changed to fit with Guice.
     */
    private static final Logger LOGGER = DefaultLoggerFactory.get(ObjectIdFactory.class);

    private static final int MACHINE_ID = createMachineId();
    private static final int PROCESS_ID = createProcessId();
    private static final AtomicInteger COUNTER = new AtomicInteger(new SecureRandom().nextInt());

    public BsonObjectId consumeObjectId() {
        long secs = System.currentTimeMillis() / 1000;
        return new IntBasedBsonObjectId(UnsignedInteger.valueOf(secs).intValue(), MACHINE_ID, PROCESS_ID,
                COUNTER.getAndIncrement() & 0xFFFFFF);
    }

    private static int createMachineId() {
        int machineId;
        try {
            Hasher hasher = Hashing.crc32c().newHasher();
            Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
            boolean atLeastOne = false;
            while (nics.hasMoreElements()) {
                NetworkInterface ni = nics.nextElement();
                if (ni != null) {
                    byte[] macAddress = ni.getHardwareAddress();
                    if (macAddress != null) {
                        for (byte b : macAddress) {
                            atLeastOne = true;
                            hasher.putByte(b);
                        }
                    }
                }
            }
            if (!atLeastOne) {
                LOGGER.warn("Failed to calculate the machine id. A random number is used");
                machineId = new SecureRandom().nextInt();
            } else {
                machineId = hasher.hash().asInt();
            }
        } catch (SocketException ex) {
            LOGGER.warn("Failed to calculate the machine id. A random number is used");
            machineId = new SecureRandom().nextInt();
        }

        return machineId & 0xFFFFFF;
    }

    private static int createProcessId() {
        int pid;
        String name = ManagementFactory.getRuntimeMXBean().getName();
        try {
            pid = Integer.parseInt(name.substring(0, name.indexOf("@")));
        } catch (Throwable ex) {
            LOGGER.warn("Failed to calculate the process id. A random number is used");
            pid = new SecureRandom().nextInt();
        }
        return pid & 0xFFFF;
    }

}