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 */ 017package org.apache.activemq.util; 018 019import java.net.ServerSocket; 020import java.util.concurrent.atomic.AtomicLong; 021 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024 025/** 026 * Generator for Globally unique Strings. 027 */ 028 029public 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", ioe); 060 } 061 } else { 062 hostName = "localhost"; 063 stub = "-1-" + System.currentTimeMillis() + "-"; 064 } 065 UNIQUE_STUB = stub; 066 } 067 068 /** 069 * Construct an IdGenerator 070 */ 071 public IdGenerator(String prefix) { 072 synchronized (UNIQUE_STUB) { 073 this.seed = prefix + UNIQUE_STUB + (instanceCount++) + ":"; 074 this.length = this.seed.length() + ("" + Long.MAX_VALUE).length(); 075 } 076 } 077 078 public IdGenerator() { 079 this("ID:" + hostName); 080 } 081 082 /** 083 * As we have to find the hostname as a side-affect of generating a unique 084 * stub, we allow it's easy retrevial here 085 * 086 * @return the local host name 087 */ 088 089 public static String getHostName() { 090 return hostName; 091 } 092 093 094 /** 095 * Generate a unqiue id 096 * 097 * @return a unique id 098 */ 099 100 public synchronized String generateId() { 101 StringBuilder sb = new StringBuilder(length); 102 sb.append(seed); 103 sb.append(sequence.getAndIncrement()); 104 return sb.toString(); 105 } 106 107 /** 108 * Generate a unique ID - that is friendly for a URL or file system 109 * 110 * @return a unique id 111 */ 112 public String generateSanitizedId() { 113 String result = generateId(); 114 result = result.replace(':', '-'); 115 result = result.replace('_', '-'); 116 result = result.replace('.', '-'); 117 return result; 118 } 119 120 /** 121 * From a generated id - return the seed (i.e. minus the count) 122 * 123 * @param id the generated identifer 124 * @return the seed 125 */ 126 public static String getSeedFromId(String id) { 127 String result = id; 128 if (id != null) { 129 int index = id.lastIndexOf(':'); 130 if (index > 0 && (index + 1) < id.length()) { 131 result = id.substring(0, index + 1); 132 } 133 } 134 return result; 135 } 136 137 /** 138 * From a generated id - return the generator count 139 * 140 * @param id 141 * @return the count 142 */ 143 public static long getSequenceFromId(String id) { 144 long result = -1; 145 if (id != null) { 146 int index = id.lastIndexOf(':'); 147 148 if (index > 0 && (index + 1) < id.length()) { 149 String numStr = id.substring(index + 1, id.length()); 150 result = Long.parseLong(numStr); 151 } 152 } 153 return result; 154 } 155 156 /** 157 * Does a proper compare on the ids 158 * 159 * @param id1 160 * @param id2 161 * @return 0 if equal else a positive if id1 is > id2 ... 162 */ 163 164 public static int compare(String id1, String id2) { 165 int result = -1; 166 String seed1 = IdGenerator.getSeedFromId(id1); 167 String seed2 = IdGenerator.getSeedFromId(id2); 168 if (seed1 != null && seed2 != null) { 169 result = seed1.compareTo(seed2); 170 if (result == 0) { 171 long count1 = IdGenerator.getSequenceFromId(id1); 172 long count2 = IdGenerator.getSequenceFromId(id2); 173 result = (int)(count1 - count2); 174 } 175 } 176 return result; 177 178 } 179 180}