001 /** 002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved. 003 * Licensed under the Apache License, Version 2.0 (the "License"); 004 * you may not use this file except in compliance with the License. 005 * You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software 010 * distributed under the License is distributed on an "AS IS" BASIS, 011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 * See the License for the specific language governing permissions and 013 * limitations under the License. See accompanying LICENSE file. 014 */ 015 package org.apache.oozie.service; 016 017 import org.apache.oozie.util.ParamChecker; 018 import org.apache.oozie.util.XLog; 019 import org.apache.oozie.ErrorCode; 020 021 import java.text.SimpleDateFormat; 022 import java.util.Date; 023 import java.util.UUID; 024 import java.util.concurrent.atomic.AtomicLong; 025 026 /** 027 * The UUID service generates unique IDs. <p/> The configuration property {@link #CONF_GENERATOR} specifies the ID 028 * generation type, 'random' or 'counter'. <p/> For 'random' uses the JDK UUID.randomUUID() method. <p/> For 'counter' 029 * uses a counter postfixed wit the system start up time. 030 */ 031 public class UUIDService implements Service { 032 033 public static final String CONF_PREFIX = Service.CONF_PREFIX + "UUIDService."; 034 035 public static final String CONF_GENERATOR = CONF_PREFIX + "generator"; 036 037 private String startTime; 038 private AtomicLong counter; 039 private String systemId; 040 041 /** 042 * Initialize the UUID service. 043 * 044 * @param services services instance. 045 * @throws ServiceException thrown if the UUID service could not be initialized. 046 */ 047 @Override 048 public void init(Services services) throws ServiceException { 049 String genType = services.getConf().get(CONF_GENERATOR, "counter").trim(); 050 if (genType.equals("counter")) { 051 counter = new AtomicLong(); 052 startTime = new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date()); 053 } 054 else { 055 if (!genType.equals("random")) { 056 throw new ServiceException(ErrorCode.E0120, genType); 057 } 058 } 059 systemId = services.getSystemId(); 060 } 061 062 /** 063 * Destroy the UUID service. 064 */ 065 @Override 066 public void destroy() { 067 counter = null; 068 startTime = null; 069 } 070 071 /** 072 * Return the public interface for UUID service. 073 * 074 * @return {@link UUIDService}. 075 */ 076 @Override 077 public Class<? extends Service> getInterface() { 078 return UUIDService.class; 079 } 080 081 private String longPadding(long number) { 082 StringBuilder sb = new StringBuilder(); 083 sb.append(number); 084 if (sb.length() <= 7) { 085 sb.insert(0, "0000000".substring(sb.length())); 086 } 087 return sb.toString(); 088 } 089 090 /** 091 * Create a unique ID. 092 * 093 * @param type: Type of Id. Generally 'C' for Coordinator and 'W' for Workflow. 094 * @return unique ID. 095 */ 096 public String generateId(ApplicationType type) { 097 StringBuilder sb = new StringBuilder(); 098 099 if (counter != null) { 100 sb.append(longPadding(counter.getAndIncrement())).append('-').append(startTime); 101 } 102 else { 103 sb.append(UUID.randomUUID().toString()); 104 if (sb.length() > (37 - systemId.length())) { 105 sb.setLength(37 - systemId.length()); 106 } 107 } 108 sb.append('-').append(systemId); 109 sb.append('-').append(type.getType()); 110 // limitation due to current DB schema for action ID length (100) 111 if (sb.length() > 40) { 112 throw new RuntimeException(XLog.format("ID exceeds limit of 40 characters, [{0}]", sb)); 113 } 114 return sb.toString(); 115 } 116 117 /** 118 * Create a child ID. <p/> If the same child name is given the returned child ID is the same. 119 * 120 * @param id unique ID. 121 * @param childName child name. 122 * @return a child ID. 123 */ 124 public String generateChildId(String id, String childName) { 125 id = ParamChecker.notEmpty(id, "id") + "@" + ParamChecker.notEmpty(childName, "childName"); 126 127 // limitation due to current DB schema for action ID length (100) 128 if (id.length() > 95) { 129 throw new RuntimeException(XLog.format("Child ID exceeds limit of 95 characters, [{0}]", id)); 130 } 131 return id; 132 } 133 134 /** 135 * Return the ID from a child ID. 136 * 137 * @param childId child ID. 138 * @return ID of the child ID. 139 */ 140 public String getId(String childId) { 141 int index = ParamChecker.notEmpty(childId, "childId").indexOf("@"); 142 if (index == -1) { 143 throw new IllegalArgumentException(XLog.format("invalid child id [{0}]", childId)); 144 } 145 return childId.substring(0, index); 146 } 147 148 /** 149 * Return the child name from a child ID. 150 * 151 * @param childId child ID. 152 * @return child name. 153 */ 154 public String getChildName(String childId) { 155 int index = ParamChecker.notEmpty(childId, "childId").indexOf("@"); 156 if (index == -1) { 157 throw new IllegalArgumentException(XLog.format("invalid child id [{0}]", childId)); 158 } 159 return childId.substring(index + 1); 160 } 161 162 public enum ApplicationType { 163 WORKFLOW('W'), COORDINATOR('C'); 164 private char type; 165 166 private ApplicationType(char type) { 167 this.type = type; 168 } 169 170 public char getType() { 171 return type; 172 } 173 } 174 }