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 }