All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nervousync.utils.SnowflakeUtils Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Nervousync Studio (NSYC) 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 com.nervousync.utils;

import com.nervousync.commons.core.Globals;
import com.nervousync.utils.DateTimeUtils;
import com.nervousync.utils.SystemUtils;

/**
 * Snowflake Utility
 * @author Steven Wee	[email protected]
 * @version $Revision: 1.0 $ $Date: Jun 27, 2018 $
 */
public final class SnowflakeUtils {
	
	/**
	 * Instance object
	 */
	private static SnowflakeUtils INSTANCE = null;

	/**
	 * Default timestamp value, default is 2011-04-21 00:00 CST
	 */
	private static final long REFERENCE_TIME = 1303286400000L;
	/**
	 * Sequence mask code, sequence id bits: 12
	 */
	private static final long SEQUENCE_MASK = -1L ^ (-1L << 12L);
	/**
	 * Node identified id (between 0 and 1023)
	 */
	private static final long DEVICE_ID = SystemUtils.identifiedKey().hashCode() % 1024L;
	/**
	 * Begin timestamp value
	 */
	private long referenceTime = Globals.DEFAULT_VALUE_LONG;
	/**
	 * Sequence index in millisecond
	 */
	private long sequenceIndex = Globals.DEFAULT_VALUE_LONG;
	/**
	 * Previous generate time
	 */
	private long lastTime = Globals.DEFAULT_VALUE_LONG;
	
	/**
	 * Constructor
	 * @param referenceTime		Reference time value
	 */
	private SnowflakeUtils(long referenceTime) {
		if (referenceTime < 0L) {
			this.referenceTime = REFERENCE_TIME;
		} else {
			this.referenceTime = referenceTime;
		}
		this.sequenceIndex = 0L;
	}
	
	/**
	 * Initialize by default reference time value
	 */
	public static void initialize() {
		initialize(Globals.DEFAULT_VALUE_LONG);
	}
	
	/**
	 * Initialize by given reference time
	 * @param referenceTime	reference time
	 */
	public static void initialize(long referenceTime) {
		if (INSTANCE == null) {
			INSTANCE = new SnowflakeUtils(referenceTime);
		}
	}
	
	/**
	 * Get utility instance
	 * @return	Snowflake utils
	 */
	public static SnowflakeUtils getInstance() {
		return SnowflakeUtils.INSTANCE;
	}
	
	/**
	 * Generate original snowflake id
	 * @return generated ID
	 */
	public long generateId() {
		if (INSTANCE == null) {
			SnowflakeUtils.initialize();
		}
		return INSTANCE.generateValue(true);
	}

	/**
	 * Generate id start with current date format as "yyyyMMdd"
	 * @param isGMT		Current day is GMT
	 * @return generated ID
	 */
	public long generateDateId(boolean isGMT) {
		if (INSTANCE == null) {
			SnowflakeUtils.initialize();
		}
		return INSTANCE.generateDateValue(isGMT);
	}

	/**
	 * Generate id start with current time format as "yyyyMMddHHmm"
	 * @param isGMT		Current time is GMT
	 * @return generated ID
	 */
	public long generateTimeId(boolean isGMT) {
		if (INSTANCE == null) {
			SnowflakeUtils.initialize();
		}
		return INSTANCE.generateTimeValue(isGMT);
	}
	
	private synchronized long generateDateValue(boolean isGMT) {
		StringBuilder stringBuilder = new StringBuilder();
		if (isGMT) {
			stringBuilder.append(DateTimeUtils.currentGMTDay());
		} else {
			stringBuilder.append(DateTimeUtils.currentDay());
		}
		stringBuilder.append(this.generateValue(false));
		return Long.parseLong(stringBuilder.toString());
	}
	
	private synchronized long generateTimeValue(boolean isGMT) {
		StringBuilder stringBuilder = new StringBuilder();
		if (isGMT) {
			stringBuilder.append(DateTimeUtils.currentGMTTime());
		} else {
			stringBuilder.append(DateTimeUtils.currentTime());
		}
		stringBuilder.append(this.generateValue(false));
		return Long.parseLong(stringBuilder.toString());
	}
	
	private synchronized long generateValue(boolean calcTime) {
		long currentTime = DateTimeUtils.currentGMTTimeMillis();
		if (currentTime < this.lastTime) {
			throw new RuntimeException(
					String.format("System clock moved backwards. Refusing to generate id for %d milliseconds", 
							this.lastTime - currentTime));
		}
		
		if (currentTime == this.lastTime) {
			this.sequenceIndex = (this.sequenceIndex + 1) & SEQUENCE_MASK;
			if (this.sequenceIndex == 0) {
				//	Out of sequence size, waiting to next second
				while ((currentTime = DateTimeUtils.currentGMTTimeMillis()) <= this.lastTime) {
				}
			}
			this.lastTime = currentTime;
		} else {
			this.sequenceIndex = 0L;
			this.lastTime = currentTime;
		}
		
		if (calcTime) {
			return ((this.lastTime - this.referenceTime) << 22L) | (DEVICE_ID << 12L) | this.sequenceIndex;
		} else {
			return (DEVICE_ID << 12L) | this.sequenceIndex;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy