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", 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 }