blob: 688230398a075aba05b1bb226f4700996b7db02a [file] [log] [blame]
/*
* 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.sling.jobs.impl;
import java.io.File;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.sling.jobs.impl.spi.MapValueAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*/
public class Utils {
private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
private static final Charset UTF8 = Charset.forName("UTF-8") ;
private static final String PROCESS_NAME = generateUniqueNamespace();
// Set the counter to the class load time.
private static final AtomicLong idCounter = new AtomicLong(System.currentTimeMillis());
/**
* Gets a string
* @return
*/
@Nonnull
private static String generateUniqueNamespace() {
String macAddress = null;
// get the MAC address of the primary interface, failing that use a fake.
try {
for ( Enumeration<NetworkInterface> netInterfaceE = NetworkInterface.getNetworkInterfaces(); netInterfaceE.hasMoreElements();) {
NetworkInterface netInterface = netInterfaceE.nextElement();
byte[] hw = netInterface.getHardwareAddress();
if ( !netInterface.isLoopback() && !netInterface.isVirtual() && hw != null) {
macAddress = tohex(hw);
LOGGER.info("Job IDs seeded with MAC Address from interface {} ", netInterface);
break;
}
}
if ( macAddress == null) {
LOGGER.info("No MAC address available, seeding JobID from startup time.");
macAddress = "fake-" + System.currentTimeMillis();
}
} catch (SocketException e) {
LOGGER.warn("Unable to get MAC address, defaulting to fake ", e);
}
long processID;
try {
// most JVMs.
processID = Long.parseLong(java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
} catch (Exception e) {
try {
// most Linux kernels.
processID = Long.parseLong(new File("/proc/self").getCanonicalFile().getName());
} catch (Exception e1) {
LOGGER.warn("Unable to get ProcessID by address, defaulting to fake ", e);
processID = System.currentTimeMillis(); // this will be way beyond any process ID.
}
}
String baseId = macAddress + "/" + processID+ "/";
LOGGER.info("Job IDS base is {} ", baseId);
return baseId;
}
@Nonnull
private static String tohex(@Nonnull byte[] bytes) {
StringBuilder sb = new StringBuilder();
for( byte b : bytes) {
sb.append(String.format("%02x",b));
}
return sb.toString();
}
/**
* Generate an ID based on the unique name of the jvm process and a counter.
* @return a generated ID.
*/
@Nonnull
public static String generateId() {
try {
return Utils.tohex(MessageDigest.getInstance("SHA1").digest((Utils.PROCESS_NAME+idCounter.incrementAndGet()).getBytes(UTF8)));
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("SHA1 not supported", nsae);
}
}
@Nonnull
public static Map<String, Object> toMapValue(@Nonnull Object msg) {
if (msg instanceof Map) {
//noinspection unchecked
return (Map<String, Object>) msg;
} else if (msg instanceof MapValueAdapter) {
return toMapValue(((MapValueAdapter) msg).toMapValue());
}
throw new IllegalArgumentException("Unable to convert "+msg.getClass()+" to a Map.");
}
@Nonnull
public static <T> T getRequired(@Nonnull Map<String, Object> m, @Nonnull String name) {
if (m.containsKey(name)) {
//noinspection unchecked
if ( m.get(name) != null) {
return (T) m.get(name);
}
}
throw new IllegalArgumentException("Required key "+name+" is missing from "+m);
}
@Nullable
public static <T> T getOptional(@Nonnull Map<String, Object> m, @Nonnull String name, @Nullable T defaultValue) {
if (m.containsKey(name)) {
//noinspection unchecked
Object o = m.get(name);
if ( defaultValue instanceof Integer && o instanceof Long) {
return (T)(Integer) ((Long) o).intValue();
} else if ( defaultValue instanceof Float && o instanceof Double) {
return (T)(Float) ((Double) o).floatValue();
}
return (T) o;
}
return defaultValue;
}
}