/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.corona; import org.apache.commons.logging.Log; import java.util.EnumMap; import java.util.List; import java.util.Iterator; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.StringTokenizer; /** * a collection of utility classes and functions */ public class Utilities { /** One unit of the compute specs */ public static final ComputeSpecs UNIT_COMPUTE_SPECS = new ComputeSpecs((short) 1); /** The pattern of the application address in the appinfo string */ public static final Pattern INET_ADDRESS_PATTERN = Pattern.compile("(.+):(\\d+)"); /** The pattern of IPAddress */ public static final Pattern IP_ADDRESS_PATTERN = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+)\\.([0-9]+)$"); /** Cache of the ResourceRequests based on the type */ private static Map<ResourceType, ResourceRequest> unitResourceRequestMap = new EnumMap<ResourceType, ResourceRequest>(ResourceType.class); /** * Do not construct this utility class. */ private Utilities() { } /** * Get a {@link ResourceRequest} object for a given resource type * Will cache the resource request after the first time it is created * * @param type the type to return the {@link ResourceRequest} for * @return the {@link ResourceRequest} object for a given type */ public static ResourceRequest getUnitResourceRequest(ResourceType type) { ResourceRequest req = unitResourceRequestMap.get(type); if (req == null) { req = new ResourceRequest(1, type); req.setSpecs(UNIT_COMPUTE_SPECS); // instead of using concurrent classes or locking - we clone and replace // the map with a new entry. this makes sense because this structure is // entirely read-only and will be populated quickly at bootstrap time HashMap<ResourceType, ResourceRequest> newMap = new HashMap<ResourceType, ResourceRequest>(); for (Map.Entry<ResourceType, ResourceRequest> entry : unitResourceRequestMap.entrySet()) { newMap.put(entry.getKey(), entry.getValue()); } newMap.put(type, req); unitResourceRequestMap = newMap; } return req; } /** * Increase the compute specs * @param target the compute specs to increase * @param incr the increment */ public static void incrComputeSpecs(ComputeSpecs target, ComputeSpecs incr) { target.numCpus += incr.numCpus; target.memoryMB += incr.memoryMB; target.diskGB += incr.diskGB; } /** * Decrease the compute specs by decr * @param target the specs to decrease * @param decr the decrement */ public static void decrComputeSpecs(ComputeSpecs target, ComputeSpecs decr) { target.numCpus -= decr.numCpus; target.memoryMB -= decr.memoryMB; target.diskGB -= decr.diskGB; } /** * Remove the object o from the list l. Different from l.remove(o) * because this method only removes it if it is the same object * @param l the list to remove from * @param o the object to remove * @return removed object if it was found in the list, null otherwise */ public static Object removeReference(List l, Object o) { Iterator iter = l.iterator(); while (iter.hasNext()) { Object no = iter.next(); if (no == o) { iter.remove(); return o; } } return null; } /** * A realiable way to wait for the thread termination * @param thread thread to wait for */ public static void waitThreadTermination(Thread thread) { while (thread != null && thread.isAlive()) { thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { } } } /** * Convert the appinfo string to the address the application is available on * @param info the string of the appinfo * @return the address application is available on */ public static InetAddress appInfoToAddress(String info) { Matcher m = INET_ADDRESS_PATTERN.matcher(info); if (m.find()) { int port = Integer.parseInt(m.group(2)); return new InetAddress(m.group(1), port); } return null; } /** * Sets an uncaught exception handler. This will make the process exit with * exit code 1 if a thread exits due to an uncaught exception. */ public static void makeProcessExitOnUncaughtException(final Log log) { Thread.setDefaultUncaughtExceptionHandler( new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { log.error("UNCAUGHT: Thread " + t.getName() + " got an uncaught exception", e); System.exit(1); } }); } public static byte[] asBytes(String addr) { // Convert the TCP/IP address string to an integer value int ipInt = parseNumericAddress(addr); if ( ipInt == 0) { return null; } byte[] ipByts = new byte[4]; ipByts[3] = (byte) (ipInt & 0xFF); ipByts[2] = (byte) ((ipInt >> 8) & 0xFF); ipByts[1] = (byte) ((ipInt >> 16) & 0xFF); ipByts[0] = (byte) ((ipInt >> 24) & 0xFF); return ipByts; } /** * Check if the specified address is a valid numeric TCP/IP address and return as an integer value * * @param ipaddr String * @return int */ public static int parseNumericAddress(String ipaddr) { Matcher m = IP_ADDRESS_PATTERN.matcher(ipaddr); int ipInt = 0; if (m.find()) { for (int i = 1;i < 5;i++) try { int ipVal = Integer.valueOf(m.group(i)).intValue(); if ( ipVal < 0 || ipVal > 255) { return 0; } // Add to the integer address ipInt = (ipInt << 8) + ipVal; } catch (NumberFormatException ex) { return 0; } } // Return the integer address return ipInt; } }