001/* 002 * Copyright 2022-2025 Revetware LLC. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.soklet.core.impl; 018 019import com.soklet.core.IdGenerator; 020 021import javax.annotation.Nonnull; 022import javax.annotation.Nullable; 023import javax.annotation.concurrent.ThreadSafe; 024import java.net.InetAddress; 025import java.util.concurrent.atomic.AtomicLong; 026 027import static java.lang.String.format; 028import static java.util.Objects.requireNonNull; 029 030/** 031 * @author <a href="https://www.revetkn.com">Mark Allen</a> 032 */ 033@ThreadSafe 034public class DefaultIdGenerator implements IdGenerator { 035 @Nonnull 036 private static final String DEFAULT_ID_PREFIX; 037 038 static { 039 String idPrefix = ""; 040 041 // IDs ultimately look like "192.168.4.75-1234" (or just "1234" if we can't detect host address) 042 try { 043 String hostAddress = InetAddress.getLocalHost().getHostAddress(); 044 045 if (hostAddress != null) { 046 hostAddress = hostAddress.trim(); 047 048 if (hostAddress.length() > 0) 049 idPrefix = format("%s-", hostAddress); 050 } 051 } catch (Exception e) { 052 // Ignored 053 } 054 055 DEFAULT_ID_PREFIX = idPrefix; 056 } 057 058 @Nonnull 059 private final Long minimumId; 060 @Nonnull 061 private final Long maximumId; 062 @Nonnull 063 private final AtomicLong idGenerator; 064 @Nonnull 065 private final String idPrefix; 066 067 public DefaultIdGenerator() { 068 this(1L, 9_999_999L); 069 } 070 071 public DefaultIdGenerator(@Nonnull Long minimumId, 072 @Nonnull Long maximumId) { 073 this(minimumId, maximumId, null); 074 } 075 076 public DefaultIdGenerator(@Nonnull Long minimumId, 077 @Nonnull Long maximumId, 078 @Nullable String idPrefix) { 079 requireNonNull(minimumId); 080 requireNonNull(maximumId); 081 082 if (minimumId < 0) 083 throw new IllegalArgumentException(format("Minimum ID (%s) cannot be negative", minimumId)); 084 085 if (maximumId < 1) 086 throw new IllegalArgumentException(format("Maximum ID (%s) must be greater than zero", maximumId)); 087 088 if (minimumId >= maximumId) 089 throw new IllegalArgumentException(format("Minimum ID (%s) must be less than maximum ID (%s)", minimumId, maximumId)); 090 091 if (idPrefix == null) 092 idPrefix = getDefaultIdPrefix(); 093 094 this.minimumId = minimumId; 095 this.maximumId = maximumId; 096 this.idPrefix = idPrefix; 097 this.idGenerator = new AtomicLong(getMinimumId()); 098 } 099 100 @Nonnull 101 @Override 102 public Object generateId() { 103 return format("%s%s", getIdPrefix(), getIdGenerator().getAndAccumulate(getMaximumId(), 104 (currentId, ignored) -> currentId < getMaximumId() ? ++currentId : getMinimumId())); 105 } 106 107 @Nonnull 108 protected String getDefaultIdPrefix() { 109 return DEFAULT_ID_PREFIX; 110 } 111 112 @Nonnull 113 protected AtomicLong getIdGenerator() { 114 return this.idGenerator; 115 } 116 117 @Nonnull 118 protected Long getMinimumId() { 119 return this.minimumId; 120 } 121 122 @Nonnull 123 protected Long getMaximumId() { 124 return this.maximumId; 125 } 126 127 @Nonnull 128 protected String getIdPrefix() { 129 return this.idPrefix; 130 } 131}