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    }