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 */ 017package org.apache.camel.impl; 018 019import java.util.concurrent.atomic.AtomicLong; 020 021import org.apache.camel.spi.UuidGenerator; 022import org.apache.camel.util.InetAddressUtil; 023import org.apache.camel.util.ObjectHelper; 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027/** 028 * Default {@link UuidGenerator} that is based on the {@link ActiveMQUuidGenerator} but 029 * is optimized for Camel usage to startup faster and avoid use local network binding to obtain a random number. 030 */ 031public class DefaultUuidGenerator implements UuidGenerator { 032 033 private static final Logger LOG = LoggerFactory.getLogger(DefaultUuidGenerator.class); 034 private static final String UNIQUE_STUB; 035 private static int instanceCount; 036 private static String hostName; 037 private String seed; 038 // must use AtomicLong to ensure atomic get and update operation that is thread-safe 039 private final AtomicLong sequence = new AtomicLong(1); 040 private final int length; 041 042 static { 043 String stub = ""; 044 boolean canAccessSystemProps = true; 045 try { 046 SecurityManager sm = System.getSecurityManager(); 047 if (sm != null) { 048 sm.checkPropertiesAccess(); 049 } 050 } catch (SecurityException se) { 051 canAccessSystemProps = false; 052 } 053 054 if (canAccessSystemProps) { 055 try { 056 if (hostName == null) { 057 hostName = InetAddressUtil.getLocalHostName(); 058 } 059 stub = "-" + System.currentTimeMillis() + "-"; 060 } catch (Exception e) { 061 if (LOG.isTraceEnabled()) { 062 LOG.trace("Cannot generate unique stub by using DNS", e); 063 } else { 064 LOG.warn("Cannot generate unique stub by using DNS due {}. This exception is ignored.", e.getMessage()); 065 } 066 } 067 } 068 069 // fallback to use localhost 070 if (hostName == null) { 071 hostName = "localhost"; 072 } 073 hostName = sanitizeHostName(hostName); 074 075 if (ObjectHelper.isEmpty(stub)) { 076 stub = "-1-" + System.currentTimeMillis() + "-"; 077 } 078 UNIQUE_STUB = stub; 079 } 080 081 public DefaultUuidGenerator(String prefix) { 082 synchronized (UNIQUE_STUB) { 083 this.seed = prefix + UNIQUE_STUB + (instanceCount++) + "-"; 084 // let the ID be friendly for URL and file systems 085 this.seed = generateSanitizedId(this.seed); 086 this.length = seed.length() + ("" + Long.MAX_VALUE).length(); 087 } 088 } 089 090 public DefaultUuidGenerator() { 091 this("ID-" + hostName); 092 } 093 094 /** 095 * As we have to find the hostname as a side-affect of generating a unique 096 * stub, we allow it's easy retrieval here 097 * 098 * @return the local host name 099 */ 100 public static String getHostName() { 101 return hostName; 102 } 103 104 public static String sanitizeHostName(String hostName) { 105 boolean changed = false; 106 107 StringBuilder sb = new StringBuilder(); 108 for (char ch : hostName.toCharArray()) { 109 // only include ASCII chars 110 if (ch < 127) { 111 sb.append(ch); 112 } else { 113 changed = true; 114 } 115 } 116 117 if (changed) { 118 String newHost = sb.toString(); 119 LOG.info("Sanitized hostname from: {} to: {}", hostName, newHost); 120 return newHost; 121 } else { 122 return hostName; 123 } 124 } 125 126 public String generateUuid() { 127 StringBuilder sb = new StringBuilder(length); 128 sb.append(seed); 129 sb.append(sequence.getAndIncrement()); 130 return sb.toString(); 131 } 132 133 /** 134 * Generate a unique ID - that is friendly for a URL or file system 135 * 136 * @return a unique id 137 */ 138 public String generateSanitizedId() { 139 return generateSanitizedId(generateUuid()); 140 } 141 142 /** 143 * Ensures that the id is friendly for a URL or file system 144 * 145 * @param id the unique id 146 * @return the id as file friendly id 147 */ 148 public static String generateSanitizedId(String id) { 149 id = id.replace(':', '-'); 150 id = id.replace('_', '-'); 151 id = id.replace('.', '-'); 152 id = id.replace('/', '-'); 153 return id; 154 } 155}