001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.activemq.util; 018 019 import java.net.ServerSocket; 020 import java.util.concurrent.atomic.AtomicLong; 021 022 import org.slf4j.Logger; 023 import org.slf4j.LoggerFactory; 024 025 /** 026 * Generator for Globally unique Strings. 027 */ 028 029 public class IdGenerator { 030 031 private static final Logger LOG = LoggerFactory.getLogger(IdGenerator.class); 032 private static final String UNIQUE_STUB; 033 private static int instanceCount; 034 private static String hostName; 035 private String seed; 036 private AtomicLong sequence = new AtomicLong(1); 037 private int length; 038 039 static { 040 String stub = ""; 041 boolean canAccessSystemProps = true; 042 try { 043 SecurityManager sm = System.getSecurityManager(); 044 if (sm != null) { 045 sm.checkPropertiesAccess(); 046 } 047 } catch (SecurityException se) { 048 canAccessSystemProps = false; 049 } 050 051 if (canAccessSystemProps) { 052 try { 053 hostName = InetAddressUtil.getLocalHostName(); 054 ServerSocket ss = new ServerSocket(0); 055 stub = "-" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "-"; 056 Thread.sleep(100); 057 ss.close(); 058 } catch (Exception ioe) { 059 LOG.warn("could not generate unique stub by using DNS and binding to local port", ioe); 060 } 061 } 062 // fallback 063 if (hostName == null) { 064 hostName = "localhost"; 065 } 066 if (stub.length() == 0) { 067 stub = "-1-" + System.currentTimeMillis() + "-"; 068 } 069 UNIQUE_STUB = stub; 070 } 071 072 /** 073 * Construct an IdGenerator 074 */ 075 public IdGenerator(String prefix) { 076 synchronized (UNIQUE_STUB) { 077 this.seed = prefix + UNIQUE_STUB + (instanceCount++) + ":"; 078 this.length = this.seed.length() + ("" + Long.MAX_VALUE).length(); 079 } 080 } 081 082 public IdGenerator() { 083 this("ID:" + hostName); 084 } 085 086 /** 087 * As we have to find the hostname as a side-affect of generating a unique 088 * stub, we allow it's easy retrevial here 089 * 090 * @return the local host name 091 */ 092 093 public static String getHostName() { 094 return hostName; 095 } 096 097 098 /** 099 * Generate a unqiue id 100 * 101 * @return a unique id 102 */ 103 104 public synchronized String generateId() { 105 StringBuilder sb = new StringBuilder(length); 106 sb.append(seed); 107 sb.append(sequence.getAndIncrement()); 108 return sb.toString(); 109 } 110 111 /** 112 * Generate a unique ID - that is friendly for a URL or file system 113 * 114 * @return a unique id 115 */ 116 public String generateSanitizedId() { 117 String result = generateId(); 118 result = result.replace(':', '-'); 119 result = result.replace('_', '-'); 120 result = result.replace('.', '-'); 121 return result; 122 } 123 124 /** 125 * From a generated id - return the seed (i.e. minus the count) 126 * 127 * @param id the generated identifer 128 * @return the seed 129 */ 130 public static String getSeedFromId(String id) { 131 String result = id; 132 if (id != null) { 133 int index = id.lastIndexOf(':'); 134 if (index > 0 && (index + 1) < id.length()) { 135 result = id.substring(0, index); 136 } 137 } 138 return result; 139 } 140 141 /** 142 * From a generated id - return the generator count 143 * 144 * @param id 145 * @return the count 146 */ 147 public static long getSequenceFromId(String id) { 148 long result = -1; 149 if (id != null) { 150 int index = id.lastIndexOf(':'); 151 152 if (index > 0 && (index + 1) < id.length()) { 153 String numStr = id.substring(index + 1, id.length()); 154 result = Long.parseLong(numStr); 155 } 156 } 157 return result; 158 } 159 160 /** 161 * Does a proper compare on the ids 162 * 163 * @param id1 164 * @param id2 165 * @return 0 if equal else a positive if id1 is > id2 ... 166 */ 167 168 public static int compare(String id1, String id2) { 169 int result = -1; 170 String seed1 = IdGenerator.getSeedFromId(id1); 171 String seed2 = IdGenerator.getSeedFromId(id2); 172 if (seed1 != null && seed2 != null) { 173 result = seed1.compareTo(seed2); 174 if (result == 0) { 175 long count1 = IdGenerator.getSequenceFromId(id1); 176 long count2 = IdGenerator.getSequenceFromId(id2); 177 result = (int)(count1 - count2); 178 } 179 } 180 return result; 181 182 } 183 184 }