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.InetAddress;
020    import java.net.ServerSocket;
021    
022    import org.apache.commons.logging.Log;
023    import org.apache.commons.logging.LogFactory;
024    
025    /**
026     * Generator for Globally unique Strings.
027     */
028    
029    public class IdGenerator {
030    
031        private static final Log LOG = LogFactory.getLog(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 long sequence;
037    
038        static {
039            String stub = "";
040            boolean canAccessSystemProps = true;
041            try {
042                SecurityManager sm = System.getSecurityManager();
043                if (sm != null) {
044                    sm.checkPropertiesAccess();
045                }
046            } catch (SecurityException se) {
047                canAccessSystemProps = false;
048            }
049    
050            if (canAccessSystemProps) {
051                try {
052                    hostName = InetAddress.getLocalHost().getHostName();
053                    ServerSocket ss = new ServerSocket(0);
054                    stub = "-" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "-";
055                    Thread.sleep(100);
056                    ss.close();
057                } catch (Exception ioe) {
058                    LOG.warn("could not generate unique stub", ioe);
059                }
060            } else {
061                hostName = "localhost";
062                stub = "-1-" + System.currentTimeMillis() + "-";
063            }
064            UNIQUE_STUB = stub;
065        }
066    
067        /**
068         * Construct an IdGenerator
069         */
070        public IdGenerator(String prefix) {
071            synchronized (UNIQUE_STUB) {
072                this.seed = prefix + UNIQUE_STUB + (instanceCount++) + ":";
073            }
074        }
075    
076        public IdGenerator() {
077            this("ID:" + hostName);
078        }
079    
080        /**
081         * As we have to find the hostname as a side-affect of generating a unique
082         * stub, we allow it's easy retrevial here
083         * 
084         * @return the local host name
085         */
086    
087        public static String getHostName() {
088            return hostName;
089        }
090    
091    
092        /**
093         * Generate a unqiue id
094         * 
095         * @return a unique id
096         */
097    
098        public synchronized String generateId() {
099            return this.seed + (this.sequence++);
100        }
101    
102        /**
103         * Generate a unique ID - that is friendly for a URL or file system
104         * 
105         * @return a unique id
106         */
107        public String generateSanitizedId() {
108            String result = generateId();
109            result = result.replace(':', '-');
110            result = result.replace('_', '-');
111            result = result.replace('.', '-');
112            return result;
113        }
114    
115        /**
116         * From a generated id - return the seed (i.e. minus the count)
117         * 
118         * @param id the generated identifer
119         * @return the seed
120         */
121        public static String getSeedFromId(String id) {
122            String result = id;
123            if (id != null) {
124                int index = id.lastIndexOf(':');
125                if (index > 0 && (index + 1) < id.length()) {
126                    result = id.substring(0, index + 1);
127                }
128            }
129            return result;
130        }
131    
132        /**
133         * From a generated id - return the generator count
134         * 
135         * @param id
136         * @return the count
137         */
138        public static long getSequenceFromId(String id) {
139            long result = -1;
140            if (id != null) {
141                int index = id.lastIndexOf(':');
142    
143                if (index > 0 && (index + 1) < id.length()) {
144                    String numStr = id.substring(index + 1, id.length());
145                    result = Long.parseLong(numStr);
146                }
147            }
148            return result;
149        }
150    
151        /**
152         * Does a proper compare on the ids
153         * 
154         * @param id1
155         * @param id2
156         * @return 0 if equal else a positive if id1 is > id2 ...
157         */
158    
159        public static int compare(String id1, String id2) {
160            int result = -1;
161            String seed1 = IdGenerator.getSeedFromId(id1);
162            String seed2 = IdGenerator.getSeedFromId(id2);
163            if (seed1 != null && seed2 != null) {
164                result = seed1.compareTo(seed2);
165                if (result == 0) {
166                    long count1 = IdGenerator.getSequenceFromId(id1);
167                    long count2 = IdGenerator.getSequenceFromId(id2);
168                    result = (int)(count1 - count2);
169                }
170            }
171            return result;
172    
173        }
174    
175    }