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.camel.impl;
018    
019    import java.net.ServerSocket;
020    import java.util.concurrent.atomic.AtomicLong;
021    
022    import org.apache.camel.spi.UuidGenerator;
023    import org.apache.camel.util.InetAddressUtil;
024    import org.apache.camel.util.ObjectHelper;
025    import org.slf4j.Logger;
026    import org.slf4j.LoggerFactory;
027    
028    /**
029     * {@link org.apache.camel.spi.UuidGenerator} which is a fast implementation based on
030     * how <a href="http://activemq.apache.org/>Apache ActiveMQ</a> generates its UUID.
031     * <p/>
032     * This implementation is not synchronized but it leverages API which may not be accessible
033     * in the cloud (such as Google App Engine).
034     */
035    public class ActiveMQUuidGenerator implements UuidGenerator {
036    
037        private static final transient Logger LOG = LoggerFactory.getLogger(ActiveMQUuidGenerator.class); 
038        private static final String UNIQUE_STUB;
039        private static int instanceCount;
040        private static String hostName;
041        private String seed;
042        private final AtomicLong sequence = new AtomicLong(1);
043        private final int length;
044    
045        static {
046            String stub = "";
047            boolean canAccessSystemProps = true;
048            try {
049                SecurityManager sm = System.getSecurityManager();
050                if (sm != null) {
051                    sm.checkPropertiesAccess();
052                }
053            } catch (SecurityException se) {
054                canAccessSystemProps = false;
055            }
056    
057            if (canAccessSystemProps) {
058                try {
059                    hostName = InetAddressUtil.getLocalHostName();
060                    ServerSocket ss = new ServerSocket(0);
061                    stub = "-" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "-";
062                    Thread.sleep(100);
063                    ss.close();
064                } catch (Exception ioe) {
065                    LOG.warn("Could not generate unique stub by using DNS and binding to local port, will fallback and use localhost as name", ioe);
066                }
067            }
068    
069            // fallback to use localhost
070            if (hostName == null) {
071                hostName = "localhost";
072            }
073    
074            if (ObjectHelper.isEmpty(stub)) {
075                stub = "-1-" + System.currentTimeMillis() + "-";
076            }
077            UNIQUE_STUB = stub;
078        }
079    
080        public ActiveMQUuidGenerator(String prefix) {
081            synchronized (UNIQUE_STUB) {
082                this.seed = prefix + UNIQUE_STUB + (instanceCount++) + "-";
083                // let the ID be friendly for URL and file systems
084                this.seed = generateSanitizedId(this.seed);
085                this.length = seed.length() + ("" + Long.MAX_VALUE).length();
086            }
087        }
088    
089        public ActiveMQUuidGenerator() {
090            this("ID-" + hostName);
091        }
092    
093        /**
094         * As we have to find the hostname as a side-affect of generating a unique
095         * stub, we allow it's easy retrieval here
096         * 
097         * @return the local host name
098         */
099        public static String getHostName() {
100            return hostName;
101        }
102    
103        public String generateUuid() {
104            StringBuilder sb = new StringBuilder(length);
105            sb.append(seed);
106            sb.append(sequence.getAndIncrement());
107            return sb.toString();
108        }
109    
110        /**
111         * Generate a unique ID - that is friendly for a URL or file system
112         * 
113         * @return a unique id
114         */
115        public String generateSanitizedId() {
116            return generateSanitizedId(generateUuid());
117        }
118    
119        /**
120         * Ensures that the id is friendly for a URL or file system
121         *
122         * @param id the unique id
123         * @return the id as file friendly id
124         */
125        public static String generateSanitizedId(String id) {
126            id = id.replace(':', '-');
127            id = id.replace('_', '-');
128            id = id.replace('.', '-');
129            id = id.replace('/', '-');
130            return id;
131        }
132    }