001    /** 
002     * 
003     * Copyright 2004 Protique Ltd
004     * 
005     * Licensed under the Apache License, Version 2.0 (the "License"); 
006     * you may not use this file except in compliance with the License. 
007     * 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     **/
018    package org.activemq.util;
019    
020    import org.apache.commons.logging.Log;
021    import org.apache.commons.logging.LogFactory;
022    
023    import java.net.InetAddress;
024    import java.net.ServerSocket;
025    
026    /**
027     * Generator for globally unique Strings
028     *
029     * @version $Revision: 1.1.1.1 $
030     */
031    public class IdGenerator {
032        private static final Log log = LogFactory.getLog(IdGenerator.class);
033        private static final String UNIQUE_STUB;
034        private static int instanceCount;
035        private static String hostName;
036        private String seed;
037        private long sequence;
038        private short shortSequence;
039    
040        static {
041            String stub = "";
042            boolean canAccessSystemProps = true;
043            try {
044                SecurityManager sm = System.getSecurityManager();
045                if (sm != null) {
046                    sm.checkPropertiesAccess();
047                }
048            }
049            catch (SecurityException se) {
050                canAccessSystemProps = false;
051            }
052            if (canAccessSystemProps) {
053                try {
054                    hostName = InetAddress.getLocalHost().getHostName();
055                    ServerSocket ss = new ServerSocket(0);
056                    stub = "ID:" + hostName + "-" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "-";
057                    Thread.sleep(100);
058                    ss.close();
059                }
060                catch (Exception ioe) {
061                    log.warn("could not generate unique stub", ioe);
062                }
063            }
064            else {
065                hostName = "localhost";
066                stub = "ID:" + hostName + "-1-" + System.currentTimeMillis() + "-";
067            }
068            UNIQUE_STUB = stub;
069        }
070    
071        /**
072         * As we have to find the hostname as a side-affect of generating a unique stub, we allow it's easy retrevial here
073         *
074         * @return the local host name
075         */
076        public static String getHostName() {
077            return hostName;
078        }
079    
080        /**
081         * Construct an IdGenerator
082         */
083        public IdGenerator() {
084            synchronized (UNIQUE_STUB) {
085                this.seed = UNIQUE_STUB + (instanceCount++) + ":";
086            }
087        }
088        
089        /**
090         * Construct an IdGenerator using the seed provided
091         * @param seed
092         */
093        public IdGenerator(String seed){
094            this.seed = seed;
095        }
096        
097    
098        /**
099         * Generate a unqiue id
100         *
101         * @return a unique id
102         */
103        public synchronized String generateId() {
104            return this.seed + (this.sequence++);
105        }
106    
107        /**
108         * @return the unique seed used by this generator
109         */
110        public String getSeed() {
111            return seed;
112        }
113        
114        /**
115         * @return the next sequence
116         */
117        public synchronized long getNextSequence(){
118            return this.sequence++;
119        }
120        
121        /**
122         * @return the next short sequence
123         */
124        public synchronized short getNextShortSequence(){
125            //need to start with 1 for some wire protocols
126            return ++this.shortSequence;
127        }
128    
129        /**
130         * From a generated id - return the seed (i.e. minus the count)
131         *
132         * @param id the generated identifer
133         * @return
134         */
135        public static String getSeedFromId(String id) {
136            String result = id;
137            if (id != null) {
138                int index = id.lastIndexOf(':');
139                if (index > 0 && (index + 1) < id.length()) {
140                    result = id.substring(0, index + 1);
141                }
142            }
143            return result;
144        }
145    
146        /**
147         * From a generated id - return the generator count
148         *
149         * @param id
150         * @return the count
151         */
152        public static long getCountFromId(String id) {
153            long result = -1;
154            if (id != null) {
155                int index = id.lastIndexOf(':');
156    
157                if (index > 0 && (index + 1) < id.length()) {
158                    String numStr = id.substring(index + 1, id.length());
159                    result = Long.parseLong(numStr);
160                }
161            }
162            return result;
163        }
164    
165        /**
166         * Does a proper compare on the ids
167         *
168         * @param id1
169         * @param id2
170         * @return
171         */
172    
173        public static int compare(String id1, String id2) {
174            int result = -1;
175            String seed1 = IdGenerator.getSeedFromId(id1);
176            String seed2 = IdGenerator.getSeedFromId(id2);
177            if (seed1 != null && seed2 != null) {
178                result = seed1.compareTo(seed2);
179                if (result == 0) {
180                    long count1 = IdGenerator.getCountFromId(id1);
181                    long count2 = IdGenerator.getCountFromId(id2);
182                    result = (int) (count1 - count2);
183                }
184            }
185            return result;
186    
187        }
188    }