├── DEPENDENCIES ├── .gitignore ├── .travis.yml ├── NOTICE ├── README.md ├── pmd.xml ├── checkstyle.xml ├── LICENSE ├── src ├── test │ └── java │ │ └── org │ │ └── fintx │ │ └── util │ │ └── UniqueIdTest.java └── main │ └── java │ └── org │ └── fintx │ └── util │ └── UniqueId.java └── pom.xml /DEPENDENCIES: -------------------------------------------------------------------------------- 1 | * intentionally left blank * 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | #* 3 | *# 4 | .#* 5 | .classpath 6 | .project 7 | .settings/ 8 | .springBeans 9 | target/ 10 | bin/ 11 | _site/ 12 | .idea 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .factorypath 17 | *.log 18 | .shelf 19 | *.swp 20 | *.swo 21 | /.checkstyle 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | jdk: 8 | - oraclejdk8 9 | 10 | env: 11 | global: 12 | - JAVA_OPTS="-Xmx2G" 13 | - MAVEN_OPTS="-Xmx2G" 14 | 15 | before_script: 16 | - echo $JAVA_OPTS 17 | - echo $MAVEN_OPTS 18 | 19 | script: 20 | - mvn test 21 | 22 | after_success: 23 | - mvn coveralls:report -Ptravis -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2017 FinTx 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## FinTx Identifier Generator 2 | 3 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.fintx/fintx-identifier/badge.svg?style=flat-square)](https://maven-badges.herokuapp.com/maven-central/org.fintx/fintx-identifier/) 4 | [![GitHub release](https://img.shields.io/github/release/fintx/fintx-identifier.svg)](https://github.com/fintx/fintx-identifier/releases) 5 | ![Apache 2](http://img.shields.io/badge/license-Apache%202-red.svg) 6 | [![Join the chat at https://gitter.im/fintx/fintx-identifier](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fintx/fintx-identifier?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | [![Build Status](https://travis-ci.org/fintx/fintx-identifier.svg?branch=master)](https://travis-ci.org/fintx/fintx-identifier) 8 | [![Coverage Status](https://coveralls.io/repos/github/fintx/fintx-identifier/badge.svg)](https://coveralls.io/github/fintx/fintx-identifier) 9 | [![Dependency Status](https://www.versioneye.com/user/projects/598c0fa3368b0838815ce60c/badge.svg?style=flat)](https://www.versioneye.com/user/projects/598c0fa3368b0838815ce60c) 10 | 11 | 12 | # FinTx[1] 13 | 14 | ## What's is FinTx? 15 | 16 | FinTx is an open source group focus on financial technologies. 17 | 18 | ## What's is fintx-identifier 19 | 20 | fintx-identifier is for generating unique id in high performance and distribution environment. It extends the mongodb's ObjectId that using full MAC address to prevent the duplicated Id. It does not depend on the seeds like snowflake id generator. It can generate both 20 charachers base64 URL safe id (recommend) and 30 characters hex character id. Both id characters are in sequence that not random. 21 | 22 | ## Structure 23 | 24 |

Consists of 15 bytes, divided as follows:

25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
UniqueId layout
01234567891011121314
timemachinepidcounter
34 | 35 | ## Limitations 36 | 1. ProcessId on os could not bigger then 65535 (the default max value in most linux OS). 37 | 2. Only in one bundle of same JVM when using OSGI. 38 | 3. Id requirement could not more then about 16777215 per second per JVM. 39 | 4. Maybe it will generate duplicated id every (2^32 - 1)/(60 * 60 * 24 * 365)≈136.19 years with same machine and same process(no possible). 40 | 41 | ## Using 42 | This is something that you get for free just by adding the following dependency inside your project: 43 | 44 | ```xml 45 | 46 | org.fintx 47 | fintx-identifer 48 | ${latest.version> 49 | 50 | ``` 51 | ## Example 52 | 1. Get a 20 characters length unique id. 53 | 54 | ```java 55 | String id = UniqueId.get().toBase64String(); 56 | ``` 57 | 2. Parse id to get timestamp, machine identifier (physical MAC address), process identifier, counter number. 58 | 59 | ```java 60 | UniqueId uniqueId = UniqueId.fromBase64String(id); 61 | long timestamp = uniqueId.getTimestamp(); 62 | long machineId = uniqueId.getMachineIdentifier(); 63 | int processId = uniqueId.getProcessIdentifier(); 64 | long counter = uniqueId.getCounter(); 65 | ``` 66 | 67 | [1] FinTx https://www.fintx.org/ 68 | [2] Maven https://maven.apache.org/ 69 | -------------------------------------------------------------------------------- /pmd.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 24 | 25 | 26 | From:https://maven.apache.org/plugins/maven-pmd-plugin/examples/usingRuleSets.html 27 | The default ruleset used by the Maven PMD Plugin, when no other ruleset is specified. 28 | It contains the rules of the old (pre PMD 6.0.0) rulesets java-basic, java-empty, java-imports, 29 | java-unnecessary, java-unusedcode. 30 | 31 | This ruleset might be used as a starting point for an own customized ruleset [0]. 32 | 33 | [0] https://pmd.github.io/latest/pmd_userdocs_understanding_rulesets.html 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/test/java/org/fintx/util/UniqueIdTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FinTx 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.fintx.util; 17 | 18 | import org.junit.Assert; 19 | import org.junit.Rule; 20 | import org.junit.Test; 21 | import org.junit.rules.ExpectedException; 22 | 23 | import java.lang.reflect.InvocationTargetException; 24 | import java.lang.reflect.Method; 25 | import java.util.ArrayList; 26 | import java.util.Date; 27 | import java.util.HashSet; 28 | import java.util.List; 29 | import java.util.Set; 30 | import java.util.UUID; 31 | 32 | /** 33 | * @author bluecreator(qiang.x.wang@gmail.com) 34 | * 35 | */ 36 | public class UniqueIdTest { 37 | public int count = 2000000; 38 | public int threads = 4; 39 | public boolean error = false; 40 | 41 | @Rule 42 | public ExpectedException thrown = ExpectedException.none(); 43 | 44 | @Test 45 | public void testSingleThread() { 46 | /* 47 | * use reflect to test unreachable methods try { Method getDate_long = UniqueId.class.getMethod("getDate", new Class[] { long.class }); 48 | * 49 | * Date result =(Date) getDate_long.invoke(null, new Object[] { 123 }); } catch (IllegalAccessException | IllegalArgumentException | 50 | * InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated 51 | * catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } 52 | */ 53 | for (int i = 0; i < threads; i++) { 54 | doTest().clear(); 55 | } 56 | 57 | } 58 | 59 | @Test 60 | public void testMultiThread() { 61 | Set totalSet = new HashSet(threads * count); 62 | List> list = new ArrayList>(); 63 | for (int i = 0; i < threads; i++) { 64 | Thread t1 = new Thread(new Runnable() { 65 | 66 | @Override 67 | public void run() { 68 | try { 69 | Set set = doTest(); 70 | synchronized (list) { 71 | list.add(set); 72 | } 73 | } catch (Throwable t) { 74 | t.printStackTrace(); 75 | error = true; 76 | } 77 | 78 | } 79 | 80 | }); 81 | t1.start(); 82 | } 83 | System.err.println(""); 84 | while ((list.size() != threads) && !error) { 85 | System.err.print(list.size()); 86 | try { 87 | Thread.sleep(1000); 88 | } catch (InterruptedException e) { 89 | // TODO Auto-generated catch block 90 | e.printStackTrace(); 91 | } 92 | 93 | } 94 | System.err.println(list.size()); 95 | for (int i = 0; i < threads; i++) { 96 | totalSet.addAll(list.get(0)); 97 | list.get(0).clear(); 98 | list.remove(0); 99 | } 100 | Assert.assertTrue(totalSet.size() == threads * count); 101 | // System.err.println("The id number sum compare result:" + (set.size() == threads * count)); 102 | } 103 | 104 | public Set doTest() { 105 | UniqueId uniqueId = UniqueId.get(); 106 | String uniqueId20 = null; 107 | String uniqueId30 = null; 108 | // check length 109 | for (int i = 0; i < count; i++) { 110 | uniqueId20 = UniqueId.getString(); 111 | Assert.assertTrue("not 20 character id:" + uniqueId20, 20 == uniqueId20.length()); 112 | } 113 | for (int i = 0; i < count; i++) { 114 | uniqueId20 = UniqueId.get().toString(); 115 | Assert.assertTrue("not 20 character id:" + uniqueId20, 20 == uniqueId20.length()); 116 | } 117 | for (int i = 0; i < count; i++) { 118 | uniqueId20 = UniqueId.get().toBase64String(); 119 | Assert.assertTrue("not 20 character id:" + uniqueId20, 20 == uniqueId20.length()); 120 | } 121 | for (int i = 0; i < count; i++) { 122 | uniqueId30 = UniqueId.get().toHexString(); 123 | Assert.assertTrue("not 30 character id:" + uniqueId30, 30 == uniqueId30.length()); 124 | } 125 | 126 | // check performance 127 | long begin = System.currentTimeMillis(); 128 | for (int i = 0; i < count; i++) { 129 | uniqueId20 = UniqueId.get().toBase64String(); 130 | } 131 | long end = System.currentTimeMillis(); 132 | System.out.println("Base64 ID generation total count:" + count + " total milliseconds:" + (end - begin) + " total seconds:" + (end - begin) / 1000); 133 | System.out.println("Base64 ID generation QPS:" + count * 1000L / ((end - begin))); 134 | 135 | // check encode decode safety 136 | 137 | for (int i = 0; i < count; i++) { 138 | UniqueId temp = null; 139 | temp = UniqueId.get(); 140 | uniqueId30 = temp.toHexString(); 141 | uniqueId20 = temp.toBase64String(); 142 | Assert.assertFalse("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 143 | UniqueId.isValid(UUID.randomUUID().toString().substring(0, 30))); 144 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId20, 145 | UniqueId.isValid(UUID.randomUUID().toString().substring(0, 20))); 146 | Assert.assertFalse("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 147 | UniqueId.isValid(UUID.randomUUID().toString().toUpperCase().substring(0, 30))); 148 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId20, 149 | UniqueId.isValid(UUID.randomUUID().toString().toUpperCase().substring(0, 20))); 150 | Assert.assertFalse("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, UniqueId.isValid(UUID.randomUUID().toString())); 151 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, UniqueId.isValid(uniqueId30)); 152 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, UniqueId.isValid(uniqueId20)); 153 | 154 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, temp.equals(UniqueId.fromHexString(uniqueId30))); 155 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, temp.equals(UniqueId.fromBase64String(uniqueId20))); 156 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, temp.equals(UniqueId.fromByteArray(temp.toByteArray()))); 157 | 158 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 159 | uniqueId30.equals(UniqueId.fromBase64String(uniqueId20).toHexString())); 160 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 161 | uniqueId30.equals(UniqueId.fromByteArray(temp.toByteArray()).toHexString())); 162 | 163 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 164 | uniqueId20.equals(UniqueId.fromHexString(uniqueId30).toBase64String())); 165 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 166 | uniqueId20.equals(UniqueId.fromByteArray(temp.toByteArray()).toBase64String())); 167 | 168 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 169 | UniqueId.fromHexString(uniqueId30).getTimestamp() == UniqueId.fromBase64String(uniqueId20).getTimestamp()); 170 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 171 | UniqueId.getCurrentTimeStamp() >= UniqueId.fromBase64String(uniqueId20).getTimestamp()); 172 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 173 | UniqueId.fromHexString(uniqueId30).getMachineIdentifier() == UniqueId.fromBase64String(uniqueId20).getMachineIdentifier()); 174 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 175 | UniqueId.getGeneratedMachineIdentifier() == UniqueId.fromBase64String(uniqueId20).getMachineIdentifier()); 176 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 177 | UniqueId.fromHexString(uniqueId30).getProcessIdentifier() == UniqueId.fromBase64String(uniqueId20).getProcessIdentifier()); 178 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 179 | UniqueId.getGeneratedProcessIdentifier() == UniqueId.fromBase64String(uniqueId20).getProcessIdentifier()); 180 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 181 | UniqueId.fromHexString(uniqueId30).getCounter() == UniqueId.fromBase64String(uniqueId20).getCounter()); 182 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 183 | UniqueId.fromHexString(uniqueId30).getDate().getTime() == UniqueId.fromBase64String(uniqueId20).getDate().getTime()); 184 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 185 | UniqueId.fromHexString(uniqueId30).equals(UniqueId.fromBase64String(uniqueId20))); 186 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 187 | UniqueId.fromHexString(uniqueId30).compareTo(UniqueId.fromBase64String(uniqueId20)) == 0); 188 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 189 | UniqueId.fromHexString(uniqueId30).toString().equals(UniqueId.fromBase64String(uniqueId20).toBase64String())); 190 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, temp.equals(temp)); 191 | Assert.assertFalse("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, temp.equals(null)); 192 | Assert.assertFalse("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, temp.equals("1243543246")); 193 | Assert.assertTrue("Unsafe Base64 encode and decode, original id:" + i + " " + uniqueId30, 194 | UniqueId.fromHexString(uniqueId30).hashCode() == UniqueId.fromBase64String(uniqueId20).hashCode()); 195 | UniqueId newTemp = UniqueId.get(); 196 | Assert.assertFalse(UniqueId.fromHexString(uniqueId30).equals(newTemp)); 197 | Assert.assertFalse(newTemp.equals(temp)); 198 | Assert.assertTrue(newTemp.compareTo(temp) != 0); 199 | UniqueId.getCurrentCounter(); 200 | UniqueId.getCurrentTimeStamp(); 201 | UniqueId.getGeneratedMachineIdentifier(); 202 | UniqueId.getGeneratedProcessIdentifier(); 203 | } 204 | Assert.assertFalse(UniqueId.get().equals(uniqueId)); 205 | Assert.assertTrue(UniqueId.get().compareTo(uniqueId) != 0); 206 | Set set = new HashSet(count); 207 | for (int i = 0; i < count; i++) { 208 | 209 | uniqueId20 = UniqueId.get().toBase64String(); 210 | set.add(uniqueId20); 211 | } 212 | int size = set.size(); 213 | // set.clear(); 214 | Assert.assertTrue("Duplicated key found in originalId set." + uniqueId20, size == count); 215 | 216 | Assert.assertTrue(uniqueId.compareTo(UniqueId.get()) != 0); 217 | return set; 218 | } 219 | 220 | @Test 221 | public void testException1() { 222 | thrown.expect(IllegalArgumentException.class); 223 | thrown.expectMessage("Argument should not be null!"); 224 | UniqueId.fromBase64String(null); 225 | 226 | } 227 | 228 | @Test 229 | public void testException2() { 230 | thrown.expect(IllegalArgumentException.class); 231 | thrown.expectMessage("Argument should not be null!"); 232 | UniqueId.fromHexString(null); 233 | 234 | } 235 | 236 | @Test 237 | public void testException3() { 238 | thrown.expect(IllegalArgumentException.class); 239 | thrown.expectMessage("Argument should not be null!"); 240 | UniqueId.fromByteArray(null); 241 | 242 | } 243 | 244 | @Test 245 | public void testException4() { 246 | thrown.expect(IllegalArgumentException.class); 247 | thrown.expectMessage("invalid hexadecimal representation of an UniqueId"); 248 | UniqueId.fromBase64String(UUID.randomUUID().toString()); 249 | 250 | } 251 | 252 | @Test 253 | public void testException5() { 254 | thrown.expect(IllegalArgumentException.class); 255 | thrown.expectMessage("invalid hexadecimal representation of an UniqueId"); 256 | UniqueId.fromHexString(UUID.randomUUID().toString()); 257 | 258 | } 259 | 260 | @Test 261 | public void testException6() { 262 | thrown.expect(IllegalArgumentException.class); 263 | thrown.expectMessage("Argument need 15 bytes"); 264 | UniqueId.fromByteArray(UUID.randomUUID().toString().getBytes()); 265 | 266 | } 267 | 268 | @Test 269 | public void testException7() { 270 | thrown.expect(NullPointerException.class); 271 | UniqueId.get().compareTo(null); 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | org.fintx 6 | fintx-identifier 7 | 0.4.0.0-SNAPSHOT 8 | fintx-identifier 9 | Distributed unique id generator base on ObjectId that understandable. 10 | www.fintx.org 11 | 12 | FinTx 13 | www.fintx.org 14 | 15 | 16 | 17 | Apache License, Version 2.0 18 | http://www.apache.org/licenses/LICENSE-2.0 19 | 20 | 21 | 22 | 23 | bluecreator 24 | Qiang Wang 25 | qiang.x.wang at gmail.com 26 | FinTx 27 | www.fintx.org 28 | 29 | Project lead 30 | 31 | 32 | 33 | 34 | https://github.com/fintx/fintx-identifier 35 | scm:https://github.com/fintx/fintx-identifier.git 36 | fintx-identifier 37 | 38 | 39 | 1.8 40 | 41 | UTF-8 42 | UTF-8 43 | ${java.version} 44 | ${java.version} 45 | 46 | 47 | 48 | junit 49 | junit 50 | test 51 | 4.12 52 | 53 | 54 | 55 | ${project.artifactId} 56 | 57 | 58 | src/main/java 59 | 60 | ** 61 | 62 | false 63 | 64 | 65 | src/main/resources/ 66 | 67 | ** 68 | 69 | true 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-source-plugin 76 | 3.0.1 77 | 78 | 79 | attach-sources 80 | 81 | jar-no-fork 82 | 83 | 84 | 85 | 86 | 87 | org.apache.maven.plugins 88 | maven-javadoc-plugin 89 | 3.0.0 90 | 91 | 92 | attach-javadocs 93 | 94 | jar 95 | 96 | 97 | 98 | 99 | 100 | org.apache.maven.plugins 101 | maven-compiler-plugin 102 | 3.7.0 103 | 104 | ${java.version} 105 | ${java.version} 106 | UTF-8 107 | 108 | 109 | 110 | org.apache.maven.plugins 111 | maven-resources-plugin 112 | 3.0.1 113 | 114 | UTF-8 115 | 116 | 117 | pem 118 | pfx 119 | p12 120 | 121 | 122 | 123 | 124 | org.apache.maven.plugins 125 | maven-surefire-plugin 126 | 2.21.0 127 | 128 | 129 | -Xmx4096M ${argLine} 130 | 131 | **/*Tests.java 132 | **/*Test.java 133 | 134 | 135 | **/Abstract*.java 136 | 137 | 138 | 139 | 140 | org.apache.maven.plugins 141 | maven-dependency-plugin 142 | 3.1.1 143 | 144 | 145 | copy 146 | package 147 | 148 | tree 149 | analyze-only 150 | 151 | 152 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | org.owasp 164 | dependency-check-maven 165 | 3.2.1 166 | 167 | 168 | 169 | check 170 | 171 | 172 | 173 | 174 | true 175 | 177 | 3 178 | true 179 | 180 | 181 | 182 | org.apache.maven.plugins 183 | maven-enforcer-plugin 184 | 3.0.0-M1 185 | 186 | 187 | org.codehaus.mojo 188 | extra-enforcer-rules 189 | 1.0-beta-9 190 | 191 | 192 | 193 | 194 | enforce-check 195 | package 196 | 197 | enforce 198 | display-info 199 | 200 | 201 | 202 | 203 | false 204 | 205 | 206 | [3.0.3,) 207 | 208 | 209 | 1.8 210 | 211 | 212 | true 213 | 214 | junit:junit 215 | commons-logging:commons-logging 216 | log4j:log4j 217 | org.slf4j:slf4j-log4j12 218 | org.slf4j:slf4j-log4j13 219 | 220 | ch.qos.logback:* 221 | org.springframework:*:[,5.0.0.RELEASE]:jar 222 | commons-beanutils:commons-beanutils:[,1.8.3]:jar 223 | 224 | 225 | junit:junit:*:jar:test 226 | org.apache.logging.log4j:log4j-core:[2.10.0,] 227 | org.apache.logging.log4j:log4j-slf4j-impl:[2.10.0,] 228 | 229 | Use log4j2 and spring above 5.0.0 230 | 231 | 232 | 233 | print("[INFO] [Enforcer Rules] ");1==1 234 | 235 | 236 | 237 | true 238 | 239 | junit.* 240 | org.junit.* 241 | org.hamcrest.* 242 | org.w3c.dom.* 243 | javax.xml.* 244 | javax.annotation.* 245 | javax.activation.* 246 | org.aspectj.* 247 | com.sun.tools.attach.* 248 | com.sun.activation.* 249 | com.sun.istack.* 250 | sun.tools.attach.* 251 | org.aopalliance.* 252 | org.apache.hadoop.yarn.* 253 | org.apache.commons.beanutils.* 254 | org.apache.xmlbeans.xml.stream.* 255 | org.xml.sax.* 256 | io.netty.* 257 | 258 | [ERROR] [Enforcer Rules] find DuplicateClasses 259 | 260 | 261 | 262 | 263 | 264 | UTF-8 265 | src/main/resources/**,src/test/resources/** 266 | 267 | 268 | 269 | 270 | 271 | org.jacoco 272 | jacoco-maven-plugin 273 | 0.8.1 274 | 275 | 276 | agent-for-ut 277 | 278 | prepare-agent 279 | 280 | 281 | 282 | agent-for-it 283 | 284 | prepare-agent-integration 285 | 286 | 287 | 288 | jacoco-site 289 | verify 290 | 291 | report 292 | 293 | 294 | 295 | default-check 296 | 297 | check 298 | 299 | 300 | 301 | 302 | 303 | 304 | BUNDLE 305 | 306 | 307 | 308 | 309 | COMPLEXITY 310 | COVEREDRATIO 311 | 0.60 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | com.github.hazendaz.spotbugs 322 | spotbugs-maven-plugin 323 | 324 | 3.0.6 325 | 326 | 327 | 328 | check 329 | 330 | 331 | 332 | 333 | 334 | 335 | com.mebigfatguy.fb-contrib 336 | fb-contrib 337 | 7.4.3.sb 338 | 339 | 340 | ${project.build.sourceEncoding} 341 | java 342 | true 343 | true 344 | ${java.version} 345 | false 346 | true 347 | 348 | 349 | 350 | org.apache.maven.plugins 351 | maven-pmd-plugin 352 | 3.10.0 353 | 354 | 355 | commons-beanutils 356 | commons-beanutils 357 | 1.9.3 358 | 359 | 360 | org.dom4j 361 | dom4j 362 | 2.1.1 363 | 364 | 365 | 366 | 367 | 368 | check 369 | cpd-check 370 | 371 | 372 | 373 | 374 | ${project.build.sourceEncoding} 375 | java 376 | true 377 | true 378 | 379 | pmd.xml 380 | 381 | ${java.version} 382 | false 383 | true 384 | 385 | 386 | 387 | org.apache.maven.plugins 388 | maven-checkstyle-plugin 389 | 3.0.0 390 | 391 | 392 | 393 | check 394 | 395 | 396 | 397 | 398 | checkstyle.xml 399 | UTF-8 400 | true 401 | true 402 | true 403 | false 404 | true 405 | 406 | 407 | 408 | org.apache.maven.plugins 409 | maven-jdeps-plugin 410 | 411 | 3.1.1 412 | 413 | 414 | process-classes 415 | 416 | 417 | 418 | 419 | 420 | 421 | org.apache.maven.plugins 422 | maven-site-plugin 423 | 3.6 424 | 425 | 426 | org.apache.maven.doxia 427 | doxia-site-renderer 428 | 1.8.1 429 | 430 | 431 | commons-beanutils 432 | commons-beanutils 433 | 1.9.3 434 | 435 | 436 | org.dom4j 437 | dom4j 438 | 2.1.1 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | org.apache.maven.plugins 448 | maven-project-info-reports-plugin 449 | 3.0.0 450 | 451 | 452 | org.apache.maven.plugins 453 | maven-javadoc-plugin 454 | 455 | 456 | org.apache.maven.plugins 457 | maven-surefire-report-plugin 458 | 459 | 460 | org.codehaus.mojo 461 | jdepend-maven-plugin 462 | 2.0 463 | 464 | 465 | org.apache.maven.plugins 466 | maven-checkstyle-plugin 467 | 468 | 469 | 470 | checkstyle 471 | 472 | 473 | 474 | 475 | checkstyle.xml 476 | 477 | 478 | 479 | 480 | 481 | org.apache.maven.plugins 482 | maven-pmd-plugin 483 | 484 | ${project.build.sourceEncoding} 485 | java 486 | true 487 | 488 | pmd.xml 489 | 490 | ${java.version} 491 | 492 | 493 | 494 | com.github.hazendaz.spotbugs 495 | spotbugs-maven-plugin 496 | 497 | 498 | 499 | com.mebigfatguy.fb-contrib 500 | fb-contrib 501 | 7.4.3.sb 502 | 503 | 504 | 505 | 506 | 507 | org.apache.maven.plugins 508 | maven-jxr-plugin 509 | 510 | 512 | 513 | org.jacoco 514 | jacoco-maven-plugin 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | report 523 | 524 | 525 | 526 | 527 | 528 | org.apache.maven.plugins 529 | maven-jdeps-plugin 530 | 531 | 532 | org.apache.maven.plugins 533 | maven-dependency-plugin 534 | 3.1.1 535 | 536 | 537 | 538 | analyze-report 539 | 540 | 541 | 542 | 543 | 544 | 545 | org.owasp 546 | dependency-check-maven 547 | 548 | 549 | 550 | 551 | aggregate 552 | 553 | 554 | 555 | 556 | Dependency Security Check report 557 | 558 | 559 | 560 | org.codehaus.mojo 561 | versions-maven-plugin 562 | 563 | 564 | 565 | dependency-updates-report 566 | plugin-updates-report 567 | property-updates-report 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | release 577 | 578 | 579 | ossrh 580 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 581 | 582 | 583 | 584 | 585 | 586 | 587 | org.sonatype.plugins 588 | nexus-staging-maven-plugin 589 | 1.6.8 590 | true 591 | 592 | ossrh 593 | https://oss.sonatype.org/ 594 | true 595 | 596 | 597 | 598 | org.apache.maven.plugins 599 | maven-gpg-plugin 600 | 1.6 601 | 602 | 603 | sign-artifacts 604 | verify 605 | 606 | sign 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | false 615 | 616 | 617 | 618 | snapshot 619 | 620 | 621 | ossrh 622 | https://oss.sonatype.org/content/repositories/snapshots 623 | 624 | 625 | 626 | true 627 | 628 | 629 | 630 | travis 631 | 632 | 633 | env.TRAVIS 634 | true 635 | 636 | 637 | 638 | 639 | 640 | org.eluder.coveralls 641 | coveralls-maven-plugin 642 | 4.3.0 643 | 644 | r2OVdrdgoAv6MZsk0k3hLkuZF1vsZO0tk 645 | 646 | /target/site/jacoco/jacoco.xml 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | -------------------------------------------------------------------------------- /src/main/java/org/fintx/util/UniqueId.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 FinTx 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.fintx.util; 18 | 19 | import java.io.Serializable; 20 | import java.net.NetworkInterface; 21 | import java.security.SecureRandom; 22 | import java.util.Arrays; 23 | import java.util.Base64; 24 | import java.util.Date; 25 | import java.util.Enumeration; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | import java.util.concurrent.atomic.AtomicLong; 28 | 29 | /** 30 | *

31 | * A globally unique identifier for objects. 32 | *

33 | * 34 | *

35 | * Consists of 15 bytes, divided as follows: 36 | *

37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | *
UniqueId layout
01234567891011121314
timemachinepidcounter
63 | * 64 | *

65 | * Instances of this class are immutable. 66 | *

67 | *

68 | * Limitations: 69 | *

70 | *

71 | * ProcessId on os could not bigger then 65535. Only in one bundle of same JVM when using OSGI. Generated id number could not more then about 16777215 per 72 | * second per JVM. Id maybe (hardly) generate the same one every 69 years. 73 | *

74 | * 75 | */ 76 | //TODO 1检查long int 溢出的问题 77 | //TODO 2timestamp是否可以进一步缩短(考虑base64问题移动6bit(2^6=64)省一个字符,重复的时间缩短到1年多(69/64=?)) 78 | public final class UniqueId implements Comparable, Serializable { 79 | 80 | private static final long serialVersionUID = 3670079982654483072L; 81 | 82 | private static final int LOW_ORDER_THREE_BYTES = 0x00ffffff; 83 | 84 | private static final long MACHINE_IDENTIFIER; 85 | 86 | private static final short PROCESS_IDENTIFIER; 87 | 88 | private static final AtomicInteger NEXT_COUNTER = new AtomicInteger(new SecureRandom().nextInt()); 89 | // to prevent time change back maybe when use time server to correct the machine time. 90 | private static final AtomicLong LAST_TIMESTAMP = new AtomicLong(0); 91 | 92 | private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 93 | 94 | private final int timestamp; 95 | 96 | private final long machineIdentifier; 97 | 98 | private final short processIdentifier; 99 | 100 | private final int counter; 101 | 102 | /** 103 | * Gets a new object id. 104 | * 105 | * @return the new UniqueId instance 106 | */ 107 | public static UniqueId get() { 108 | return new UniqueId(dateToTimestampSeconds(new Date()), MACHINE_IDENTIFIER, PROCESS_IDENTIFIER, NEXT_COUNTER.getAndIncrement(), false); 109 | } 110 | 111 | /** 112 | * Gets a new object id. 113 | * 114 | * @return the new Unique Id String 115 | */ 116 | public static String getString() { 117 | return get().toString(); 118 | } 119 | 120 | /** 121 | * Checks if a string could be an {@code UniqueId}. 122 | * 123 | * @param idString hexString (base16) or base64String, a potential UniqueId as a String. 124 | * @return whether the string could be an object id 125 | * @throws IllegalArgumentException if hexString is null 126 | */ 127 | public static boolean isValid(final String idString) { 128 | if (idString == null) { 129 | throw new IllegalArgumentException("Argument should not be null!"); 130 | } 131 | 132 | int len = idString.length(); 133 | if (len == 30) { 134 | for (int i = 0; i < len; i++) { 135 | char c = idString.charAt(i); 136 | if (c >= '0' && c <= '9') { 137 | continue; 138 | } else if (c >= 'a' && c <= 'f') { 139 | continue; 140 | } else if (c >= 'A' && c <= 'F') { 141 | continue; 142 | } else { 143 | return false; 144 | } 145 | } 146 | return true; 147 | } else if (len == 20) { 148 | for (int i = 0; i < len; i++) { 149 | char c = idString.charAt(i); 150 | if (c >= '0' && c <= '9') { 151 | continue; 152 | } else if (c >= 'a' && c <= 'z') { 153 | continue; 154 | } else if (c >= 'A' && c <= 'Z') { 155 | continue; 156 | } else if (c == '_' || c == '-') { 157 | continue; 158 | } else { 159 | return false; 160 | } 161 | } 162 | return true; 163 | } else { 164 | return false; 165 | } 166 | 167 | } 168 | 169 | /** 170 | * Gets the generated machine identifier. 171 | * 172 | * @return an int representing the machine identifier 173 | */ 174 | public static long getGeneratedMachineIdentifier() { 175 | return MACHINE_IDENTIFIER; 176 | } 177 | 178 | /** 179 | * Gets the generated process identifier. 180 | * 181 | * @return the process id 182 | */ 183 | public static int getGeneratedProcessIdentifier() { 184 | return PROCESS_IDENTIFIER; 185 | } 186 | 187 | /** 188 | * Gets the current value of the auto-incrementing counter. 189 | * 190 | * @return the current counter value. 191 | */ 192 | public static int getCurrentCounter() { 193 | return NEXT_COUNTER.get(); 194 | } 195 | 196 | /** 197 | * Gets the current value of the auto-incrementing counter. 198 | * 199 | * @return the current counter value. 200 | */ 201 | public static long getCurrentTimeStamp() { 202 | return LAST_TIMESTAMP.get() & 0xffffffffL; 203 | } 204 | 205 | /** 206 | * Constructs a new instance from the timestamp 207 | * 208 | * @param timestamp of second 209 | * @param machineIdentifier the machine identifier 210 | * @param processIdentifier the process identifier 211 | * @param counter the counter in this jvm 212 | * @param checkCounter whether or not need check counter 213 | */ 214 | private UniqueId(final int timestamp, final long machineIdentifier, final short processIdentifier, final int counter, final boolean checkCounter) { 215 | long current = LAST_TIMESTAMP.get(); 216 | 217 | if ((timestamp & 0xffffffffL) == (current & 0xffffffffL)) { 218 | // @formatter:off 219 | // mostly 220 | // @formatter:on 221 | 222 | this.timestamp = timestamp; 223 | this.counter = counter & LOW_ORDER_THREE_BYTES; 224 | 225 | } else if ((timestamp & 0xffffffffL) > (current & 0xffffffffL)) { 226 | // @formatter:off 227 | // once per second or less 228 | // @formatter:on 229 | synchronized (UniqueId.class) { 230 | current = LAST_TIMESTAMP.get(); 231 | if ((timestamp & 0xffffffffL) > (current & 0xffffffffL)) { 232 | LAST_TIMESTAMP.set(timestamp & 0xffffffffL); 233 | this.timestamp = timestamp; 234 | this.counter = counter & LOW_ORDER_THREE_BYTES; 235 | } else if ((timestamp & 0xffffffffL) == (current & 0xffffffffL)) { 236 | this.timestamp = timestamp; 237 | this.counter = counter & LOW_ORDER_THREE_BYTES; 238 | } else if ((current & 0xffffffffL) - (timestamp & 0xffffffffL) == 1L) { 239 | this.timestamp = (int) current; 240 | this.counter = counter & LOW_ORDER_THREE_BYTES; 241 | } else { 242 | this.timestamp = (int) current; 243 | this.counter = NEXT_COUNTER.getAndIncrement() & LOW_ORDER_THREE_BYTES; 244 | } 245 | } 246 | } else { 247 | // @formatter:off 248 | //((timestamp & 0xffffffffL) < (current & 0xffffffffL)) 249 | // hardly 250 | // @formatter:on 251 | synchronized (UniqueId.class) { 252 | current = LAST_TIMESTAMP.get(); 253 | if ((current & 0xffffffffL) - (timestamp & 0xffffffffL) == 1L) { 254 | // @formatter:off 255 | // LAST_TIMESTAMP increased after timestamp generated 256 | // @formatter:on 257 | 258 | } else if (((LAST_TIMESTAMP.get() & 0xffffffffL) - (timestamp & 0xffffffffL)) >= 0x7fffffffL) { 259 | // timestamp is in the new round of zero to 0xffffffffL. 0x7fffffffL is half of 0xffffffffL. 260 | // A round is about 69 years, so the gap between last timestamp in the last round and new timestamp in this round will not less then 34 261 | // years. 262 | LAST_TIMESTAMP.set(timestamp & 0xffffffffL); 263 | } else { 264 | // System.err.println(((LAST_TIMESTAMP.get() & 0xffffffffL) - (timestamp & 0xffffffffL))); 265 | // System.err.println(timestamp); 266 | // System.err.println(current); 267 | // System.err.println(LAST_TIMESTAMP.get()); 268 | throw new IllegalArgumentException( 269 | "The timestamp must not be less then the timestamp last time. (Maybe the machine correct time using time server)."); 270 | } 271 | } 272 | this.counter = counter & LOW_ORDER_THREE_BYTES; 273 | this.timestamp = timestamp; 274 | } 275 | if (((machineIdentifier >> 32) & 0xff000000) != 0) { 276 | throw new IllegalArgumentException("The machine identifier must be between 0 and 28139015110655 (it must fit in six bytes)."); 277 | } 278 | if (checkCounter && ((counter & 0xff000000) != 0)) { 279 | throw new IllegalArgumentException("The counter must be between 0 and 16777215 (it must fit in three bytes)."); 280 | } 281 | this.machineIdentifier = machineIdentifier; 282 | this.processIdentifier = processIdentifier; 283 | } 284 | 285 | /** 286 | * Constructs a new instance from a 15 byte array. 287 | * 288 | * @param bytes the byte array 289 | * @return new UniqueId instance 290 | */ 291 | public static UniqueId fromByteArray(final byte[] bytes) { 292 | return new UniqueId(bytes); 293 | } 294 | 295 | /** 296 | * Constructs a new instance from a 60-byte hexadecimal (base16 encoding) string representation. 297 | * 298 | * @param hexString the string to convert 299 | * @return new UniqueId instance 300 | */ 301 | public static UniqueId fromHexString(final String hexString) { 302 | return new UniqueId(parseHexString(hexString)); 303 | } 304 | 305 | /** 306 | * Constructs a new instance from a 40-byte base64 encoding string representation. 307 | * 308 | * @param base64String the string to convert 309 | * @return new UniqueId instance 310 | */ 311 | public static UniqueId fromBase64String(final String base64String) { 312 | return new UniqueId(parseBase64String(base64String)); 313 | } 314 | 315 | /** 316 | * Constructs a new instance from the given byte array 317 | * 318 | * @param bytes the byte array 319 | */ 320 | private UniqueId(final byte[] bytes) { 321 | if (bytes == null) { 322 | throw new IllegalArgumentException("Argument should not be null!"); 323 | } 324 | if (bytes.length != 15) { 325 | throw new IllegalArgumentException("Argument need 15 bytes"); 326 | } 327 | timestamp = bytes2int(Arrays.copyOfRange(bytes, 0, 4)); 328 | machineIdentifier = bytes2long(Arrays.copyOfRange(bytes, 4, 10)); 329 | processIdentifier = (short) bytes2int(Arrays.copyOfRange(bytes, 10, 12)); 330 | counter = bytes2int(Arrays.copyOfRange(bytes, 12, 15)); 331 | } 332 | 333 | /** 334 | * Convert to a byte array. 335 | * 336 | * @return the byte array 337 | */ 338 | public byte[] toByteArray() { 339 | byte[] bytes = new byte[15]; 340 | byte[] temp = int2bytes(timestamp); 341 | bytes[0] = temp[0]; 342 | bytes[1] = temp[1]; 343 | bytes[2] = temp[2]; 344 | bytes[3] = temp[3]; 345 | temp = long2bytes(machineIdentifier); 346 | bytes[4] = temp[2]; 347 | bytes[5] = temp[3]; 348 | bytes[6] = temp[4]; 349 | bytes[7] = temp[5]; 350 | bytes[8] = temp[6]; 351 | bytes[9] = temp[7]; 352 | temp = int2bytes(processIdentifier); 353 | bytes[10] = temp[2]; 354 | bytes[11] = temp[3]; 355 | temp = int2bytes(counter); 356 | bytes[12] = temp[1]; 357 | bytes[13] = temp[2]; 358 | bytes[14] = temp[3]; 359 | return bytes; 360 | } 361 | 362 | /** 363 | * Gets the timestamp (number of seconds since the Unix epoch). 364 | * 365 | * @return the timestamp of second 366 | */ 367 | public long getTimestamp() { 368 | // To unsigned int 369 | return timestamp & 0xffffffffL; 370 | } 371 | 372 | /** 373 | * Gets the machine identifier (physical MAC address). 374 | * 375 | * @return the machine identifier 376 | */ 377 | public long getMachineIdentifier() { 378 | return machineIdentifier; 379 | } 380 | 381 | /** 382 | * Gets the process identifier. 383 | * 384 | * @return the process identifier 385 | */ 386 | public int getProcessIdentifier() { 387 | return processIdentifier & 0x0000ffff; 388 | } 389 | 390 | /** 391 | * Gets the counter. 392 | * 393 | * @return the counter 394 | */ 395 | public int getCounter() { 396 | return counter; 397 | } 398 | 399 | /** 400 | * Gets the timestamp as a {@code Date} instance. 401 | * 402 | * @return the Date 403 | */ 404 | public Date getDate() { 405 | return getDate(new Date().getTime()); 406 | } 407 | 408 | /** 409 | * Gets the timestamp as a {@code Date} instance. 410 | * 411 | * @param now the timestamp in millisecond 412 | * @return the Date 413 | */ 414 | private Date getDate(long now) { 415 | 416 | if ((timestamp & 0xffffffffL) <= (now / 1000L % 0xffffffffL)) { 417 | // @formatter:off 418 | // Timestamp is in this round of scope. 419 | // @formatter:on 420 | return new Date((((now / 1000L / 0xffffffffL) * 0xffffffffL + (timestamp & 0xffffffffL)) + now / 1000L / 0xffffffffL) * 1000L); 421 | 422 | } else if (((timestamp & 0xffffffffL) + now / 1000L / 0xffffffffL) - (now / 1000L % 0xffffffffL) >= 0x7fffffffL) { 423 | // @formatter:off 424 | // Timestamp is in last round of zero to 0xffffffffL scope. 425 | //"+ now / 1000L / 0xffffffffL" is to fix the beginning second (should be 1 but 0) every round starting from second round (the beginning is the first round) 426 | // @formatter:on 427 | return new Date((((now / 1000L / 0xffffffffL) - 1) * 0xffffffffL + (timestamp & 0xffffffffL) + (now / 1000L / 0xffffffffL) - 1) * 1000L); 428 | 429 | } else { 430 | // @formatter:off 431 | // Timestamp is in this round of zero to 0xffffffffL scope but bigger then now 432 | // @formatter:on 433 | throw new IllegalArgumentException("The timestamp must not be less then the timestamp now. (Maybe the machine correct time using time server)."); 434 | } 435 | 436 | } 437 | 438 | /** 439 | * Converts this instance into a 60-byte hexadecimal string representation. 440 | * 441 | * @return a string representation of the UniqueId in hexadecimal format 442 | */ 443 | public String toHexString() { 444 | return toHexString(toByteArray()); 445 | } 446 | 447 | /** 448 | * Converts byte array into a hexadecimal string representation. 449 | * 450 | * @param bytes the byte array 451 | * @return a string 452 | */ 453 | private static String toHexString(byte[] bytes) { 454 | char[] chars = new char[bytes.length * 2]; 455 | int i = 0; 456 | for (byte b : bytes) { 457 | chars[i++] = HEX_CHARS[b >> 4 & 0xf]; 458 | chars[i++] = HEX_CHARS[b & 0xf]; 459 | } 460 | return new String(chars); 461 | } 462 | 463 | /** 464 | * Converts this instance into a 40-byte base64 string representation. 465 | * 466 | * @return a string representation of the UniqueId in base64 format 467 | */ 468 | public String toBase64String() { 469 | return Base64.getUrlEncoder().encodeToString(toByteArray()); 470 | } 471 | 472 | @Override 473 | public boolean equals(final Object o) { 474 | if (this == o) { 475 | return true; 476 | } 477 | if (o == null || getClass() != o.getClass()) { 478 | return false; 479 | } 480 | 481 | UniqueId uniqueId = (UniqueId) o; 482 | 483 | if (counter != uniqueId.counter) { 484 | return false; 485 | } 486 | if (machineIdentifier != uniqueId.machineIdentifier) { 487 | return false; 488 | } 489 | if (processIdentifier != uniqueId.processIdentifier) { 490 | return false; 491 | } 492 | if (timestamp != uniqueId.timestamp) { 493 | return false; 494 | } 495 | 496 | return true; 497 | } 498 | 499 | @Override 500 | public int hashCode() { 501 | int result = timestamp; 502 | result = 31 * result + (int) machineIdentifier; 503 | result = 31 * result + (int) processIdentifier; 504 | result = 31 * result + counter; 505 | return result; 506 | } 507 | 508 | @Override 509 | public int compareTo(final UniqueId other) { 510 | if (other == null) { 511 | throw new NullPointerException(); 512 | } 513 | 514 | byte[] byteArray = toByteArray(); 515 | byte[] otherByteArray = other.toByteArray(); 516 | for (int i = 0; i < 15; i++) { 517 | if (byteArray[i] != otherByteArray[i]) { 518 | return ((byteArray[i] & 0xff) < (otherByteArray[i] & 0xff)) ? -1 : 1; 519 | } 520 | } 521 | return 0; 522 | } 523 | 524 | @Override 525 | public String toString() { 526 | return toBase64String(); 527 | } 528 | 529 | static { 530 | MACHINE_IDENTIFIER = createMachineIdentifier(); 531 | PROCESS_IDENTIFIER = createProcessIdentifier(); 532 | } 533 | 534 | /** 535 | * Creates the machine identifier from the physical MAC address. 536 | * 537 | * @return long the machine identifier 538 | */ 539 | private static long createMachineIdentifier() { 540 | byte[] mac = null; 541 | try { 542 | Enumeration e = NetworkInterface.getNetworkInterfaces(); 543 | while (e.hasMoreElements()) { 544 | NetworkInterface ni = e.nextElement(); 545 | if (!ni.isLoopback()) { 546 | mac = ni.getHardwareAddress(); 547 | } 548 | // ?? mac[1] != (byte) 0xff it is from http://johannburkard.de/software/uuid/ 549 | if (mac != null && mac.length == 6 && mac[1] != (byte) 0xff) { 550 | break; 551 | } else { 552 | continue; 553 | } 554 | } 555 | } catch (Throwable t) { 556 | throw new RuntimeException("Could not get MAC address", t); 557 | } 558 | if (mac != null && mac.length == 6 && mac[1] != (byte) 0xff) { 559 | return bytes2long(mac); 560 | } else { 561 | if (null == mac) { 562 | throw new RuntimeException("Could not get MAC address!"); 563 | } else { 564 | throw new RuntimeException("MAC address is not correct:" + toHexString(mac)); 565 | } 566 | } 567 | 568 | } 569 | 570 | /** 571 | * Creates the process identifier. 572 | * 573 | * @return short the process identifer 574 | */ 575 | private static short createProcessIdentifier() { 576 | short processId; 577 | try { 578 | String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); 579 | if (processName.contains("@")) { 580 | processId = (short) Integer.parseInt(processName.substring(0, processName.indexOf('@'))); 581 | } else { 582 | throw new Throwable("Process name:'" + processName + "' is invalid!"); 583 | } 584 | 585 | } catch (Throwable t) { 586 | throw new RuntimeException(t); 587 | } 588 | 589 | return processId; 590 | } 591 | 592 | /** 593 | * Parse the hexadecimal string (base16 encoding) to byte array. 594 | * 595 | * @param s the hexadecimal string 596 | * @return 597 | */ 598 | private static byte[] parseHexString(final String s) { 599 | if (!isValid(s)) { 600 | throw new IllegalArgumentException("invalid hexadecimal representation of an UniqueId: [" + s + "]"); 601 | } 602 | 603 | byte[] b = new byte[15]; 604 | for (int i = 0; i < b.length; i++) { 605 | b[i] = (byte) Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16); 606 | } 607 | return b; 608 | } 609 | 610 | /** 611 | * Parse the base64 String to byte array. 612 | * 613 | * @param s the base64 string 614 | */ 615 | private static byte[] parseBase64String(final String s) { 616 | if (!isValid(s)) { 617 | throw new IllegalArgumentException("invalid hexadecimal representation of an UniqueId: [" + s + "]"); 618 | } 619 | 620 | return Base64.getUrlDecoder().decode(s); 621 | } 622 | 623 | private static int dateToTimestampSeconds(final Date time) { 624 | return (int) ((time.getTime() / 1000L) & 0xffffffffL); 625 | } 626 | 627 | private static byte[] int2bytes(final int num) { 628 | byte[] bytes = new byte[4]; 629 | for (int ix = 0; ix < 4; ++ix) { 630 | int offset = 32 - (ix + 1) * 8; 631 | bytes[ix] = (byte) ((num >> offset) & 0xff); 632 | } 633 | return bytes; 634 | } 635 | 636 | private static int bytes2int(final byte[] bytes) { 637 | if (bytes.length > 4) { 638 | throw new RuntimeException("byteNum is too long for a int type:" + bytes.length); 639 | } 640 | int num = 0; 641 | for (int ix = 0; ix < bytes.length; ++ix) { 642 | num <<= 8; 643 | num |= (bytes[ix] & 0xff); 644 | } 645 | return num; 646 | } 647 | 648 | private static byte[] long2bytes(final long num) { 649 | byte[] bytes = new byte[8]; 650 | for (int ix = 0; ix < 8; ++ix) { 651 | int offset = 64 - (ix + 1) * 8; 652 | bytes[ix] = (byte) ((num >> offset) & 0xff); 653 | } 654 | return bytes; 655 | } 656 | 657 | private static long bytes2long(final byte[] bytes) { 658 | if (bytes.length > 8) { 659 | throw new RuntimeException("byteNum is too long for a long type:" + bytes.length); 660 | } 661 | long num = 0; 662 | for (int ix = 0; ix < bytes.length; ++ix) { 663 | num <<= 8; 664 | num |= (bytes[ix] & 0xff); // byte become 64bit since the index 1 with higher bit 1? & 0xff make higher bit 0 665 | } 666 | return num; 667 | } 668 | 669 | // public static void main(String[] args) { 670 | // //Full test!!!! 671 | // UniqueId uniqueId = null; 672 | // for (long lo = new Date().getTime(); lo > 0 && lo < Long.MAX_VALUE; lo += 100) { 673 | // uniqueId = 674 | // new UniqueId(dateToTimestampSeconds(new Date(lo)), MACHINE_IDENTIFIER, PROCESS_IDENTIFIER, 675 | // NEXT_COUNTER.getAndIncrement(), false); 676 | // if (!uniqueId.getDate(lo).toString().equals(new Date(lo / 1000L * 1000L).toString())) { 677 | // System.err.println("XXXXXXXXXXXXXXXXXXXXXXXXXXLo:" + lo); 678 | // System.err.println(uniqueId.getDate(lo).toString()); 679 | // System.err.println(new Date(lo / 1000L * 1000L).toString()); 680 | // throw new RuntimeException(); 681 | // } 682 | // if (lo / 100 % 1000000 == 0) { 683 | // System.err.println(lo); 684 | // System.err.println(uniqueId.getDate(lo).toString()); 685 | // } 686 | // } 687 | 688 | // //Function test!!!!!! 689 | // System.err.println("-------------------------------1"); 690 | // long l = 12345678901223322L; 691 | // System.err.println(Long.toBinaryString(l)); 692 | // byte[] bytes = long2bytes(l); 693 | // l = bytes2long(bytes); 694 | // System.err.println(Long.toBinaryString(l)); 695 | // int i = 1500617485; 696 | // System.err.println(Integer.toBinaryString(i)); 697 | // bytes = int2bytes(i); 698 | // l = bytes2int(bytes); 699 | // System.err.println(Long.toBinaryString(i)); 700 | 701 | // //Extreme condition test!!!!!!! 702 | // System.err.println("-------------------------------2"); 703 | // UniqueId uid = new UniqueId(dateToTimestampSeconds(new Date((Integer.MAX_VALUE - 1) * 1000L)), 704 | // MACHINE_IDENTIFIER, PROCESS_IDENTIFIER, 705 | // NEXT_COUNTER.getAndIncrement(), false); 706 | // System.err.println(uid.getDate((Integer.MAX_VALUE - 1) * 1000L).toString()); 707 | // System.err.println(uid.getTimestamp()); 708 | // System.err.println(new Date((Integer.MAX_VALUE - 1) * 1000L).toString()); 709 | // System.err.println("-------------------------------3"); 710 | // uid = new UniqueId(dateToTimestampSeconds(new Date(Integer.MAX_VALUE * 1000L)), MACHINE_IDENTIFIER, 711 | // PROCESS_IDENTIFIER, 712 | // NEXT_COUNTER.getAndIncrement(), false); 713 | // System.err.println(uid.getDate(Integer.MAX_VALUE * 1000L).toString()); 714 | // System.err.println(uid.getTimestamp()); 715 | // System.err.println(new Date(Integer.MAX_VALUE * 1000L).toString()); 716 | // System.err.println("-------------------------------4"); 717 | // uid = new UniqueId(dateToTimestampSeconds(new Date((Integer.MAX_VALUE + 1L) * 1000L)), MACHINE_IDENTIFIER, 718 | // PROCESS_IDENTIFIER, 719 | // NEXT_COUNTER.getAndIncrement(), false); 720 | // System.err.println((Integer.MAX_VALUE + 1L) * 1000L); 721 | // System.err.println(uid.getDate((Integer.MAX_VALUE + 1L) * 1000L).toString()); 722 | // System.err.println(uid.getTimestamp()); 723 | // System.err.println(new Date((Integer.MAX_VALUE + 1L) * 1000L).toString()); 724 | // System.err.println("-------------------------------5"); 725 | // uid = new UniqueId(dateToTimestampSeconds(new Date((Integer.MAX_VALUE + 2L) * 1000L)), MACHINE_IDENTIFIER, 726 | // PROCESS_IDENTIFIER, 727 | // NEXT_COUNTER.getAndIncrement(), false); 728 | // System.err.println((Integer.MAX_VALUE + 2L) * 1000L); 729 | // System.err.println(uid.getDate((Integer.MAX_VALUE + 2L) * 1000L).toString()); 730 | // System.err.println(uid.getTimestamp()); 731 | // System.err.println(new Date((Integer.MAX_VALUE + 2L) * 1000L).toString()); 732 | // System.err.println("-------------------------------6"); 733 | // System.err.println((new Date(0xfffffffeL * 1000L).getTime() / 1000L) & 0xffffffffL); 734 | // System.err.println(dateToTimestampSeconds(new Date(0xfffffffeL * 1000L))); 735 | // System.err.println(Long.toBinaryString(dateToTimestampSeconds(new Date(0xfffffffeL * 1000L)))); 736 | // System.err.println(Integer.toBinaryString((int) dateToTimestampSeconds(new Date(0xfffffffeL * 1000L)))); 737 | // uid = new UniqueId(dateToTimestampSeconds(new Date(0xfffffffeL * 1000L)), MACHINE_IDENTIFIER, 738 | // PROCESS_IDENTIFIER, 739 | // NEXT_COUNTER.getAndIncrement(), false); 740 | // System.err.println(uid.getDate(0xfffffffeL * 1000L).toString()); 741 | // System.err.println(uid.getTimestamp()); 742 | // System.err.println(new Date(0xfffffffeL * 1000L).toString()); 743 | // System.err.println("-------------------------------7"); 744 | // System.err.println((new Date(0xfffffffeL * 1000L).getTime() / 1000L) & 0xffffffffL); 745 | // System.err.println(dateToTimestampSeconds(new Date(0xffffffffL * 1000L))); 746 | // System.err.println(Long.toBinaryString(dateToTimestampSeconds(new Date(0xffffffffL * 1000L)))); 747 | // System.err.println(Integer.toBinaryString((int) dateToTimestampSeconds(new Date(0xffffffffL * 1000L)))); 748 | // uid = new UniqueId(dateToTimestampSeconds(new Date(0xffffffffL * 1000L)), MACHINE_IDENTIFIER, 749 | // PROCESS_IDENTIFIER, 750 | // NEXT_COUNTER.getAndIncrement(), false); 751 | // System.err.println(uid.getDate(0xffffffffL * 1000L).toString()); 752 | // System.err.println(uid.getTimestamp()); 753 | // System.err.println(new Date(0xffffffffL * 1000L).toString()); 754 | // System.err.println("-------------------------------8"); 755 | // uid = new UniqueId(dateToTimestampSeconds(new Date(0xffffffffL * 1000L)), MACHINE_IDENTIFIER, 756 | // PROCESS_IDENTIFIER, 757 | // NEXT_COUNTER.getAndIncrement(), false); 758 | // System.err.println(uid.getDate(0x100000000L * 1000L).toString()); 759 | // System.err.println(uid.getDate(0x100000001L * 1000L).toString()); 760 | // System.err.println(uid.getTimestamp()); 761 | // System.err.println(new Date(0xffffffffL * 1000L).toString()); 762 | // System.err.println("-------------------------------9"); 763 | // uid = new UniqueId(dateToTimestampSeconds(new Date(0x100000000L * 1000L)), MACHINE_IDENTIFIER, 764 | // PROCESS_IDENTIFIER, 765 | // NEXT_COUNTER.getAndIncrement(), false); 766 | // System.err.println(0x100000000L * 1000L); 767 | // System.err.println(uid.getDate(0x100000000L * 1000L).toString()); 768 | // System.err.println(uid.getTimestamp()); 769 | // System.err.println(new Date(0x100000000L * 1000L).getTime()); 770 | // System.err.println(new Date(0x100000000L * 1000L).toString()); 771 | // System.err.println("-------------------------------a"); 772 | // uid = new UniqueId(dateToTimestampSeconds(new Date(0x100000001L * 1000L)), MACHINE_IDENTIFIER, 773 | // PROCESS_IDENTIFIER, 774 | // NEXT_COUNTER.getAndIncrement(), false); 775 | // System.err.println(0x100000001L * 1000L); 776 | // System.err.println(uid.getDate(0x100000001L * 1000L).toString()); 777 | // System.err.println(uid.getTimestamp()); 778 | // System.err.println(new Date(0x100000001L * 1000L).getTime()); 779 | // System.err.println(new Date(0x100000001L * 1000L).toString()); 780 | // System.err.println("-------------------------------b"); 781 | // uid = new UniqueId(dateToTimestampSeconds(new Date(0x1fffffff1L * 1000L)), MACHINE_IDENTIFIER, 782 | // PROCESS_IDENTIFIER, 783 | // NEXT_COUNTER.getAndIncrement(), false); 784 | // System.err.println(0x100000001L * 1000L); 785 | // System.err.println(uid.getDate(0x200000000L * 1000L).toString()); 786 | // System.err.println(uid.getTimestamp()); 787 | // System.err.println(new Date(0x1fffffff1L * 1000L).toString()); 788 | // System.err.println(new Date(0x200000000L * 1000L).toString()); 789 | // } 790 | } 791 | --------------------------------------------------------------------------------