return UuidBinaryUtils.fromBytes(arr);
}
- /*
- * SPI UTILITIES
- */
- /** Guarantees that a byte array of length 6 will be returned. */
- protected static byte[] toNodeIdBytes(byte[] source, int offset) {
- if (source == null)
- return null;
- if (offset < 0 || offset + 6 > source.length)
- throw new ArrayIndexOutOfBoundsException(offset);
- byte[] nodeId = new byte[6];
- System.arraycopy(source, offset, nodeId, 0, 6);
- return nodeId;
- }
-
- /**
- * Force this node id to be identified as no MAC address.
- *
- * @see "https://datatracker.ietf.org/doc/html/rfc4122#section-4.5"
- */
- protected static void forceToNoMacAddress(byte[] nodeId, int offset) {
- assert nodeId != null && offset < nodeId.length;
- nodeId[offset] = (byte) (nodeId[offset] | 1);
- }
-
/*
* DIGEST UTILITIES
*/
Objects.requireNonNull(nodeId);
if (offset + 6 > nodeId.length)
throw new IllegalArgumentException("Offset too big: " + offset);
- byte[] defaultNodeId = toNodeIdBytes(nodeId, offset);
+ byte[] defaultNodeId = NodeIdSupplier.toNodeIdBytes(nodeId, offset);
long nodeIdBase = NodeIdSupplier.toNodeIdBase(defaultNodeId);
setNodeIdSupplier(() -> nodeIdBase, initialClockRange);
}
}
- public static byte[] hardwareAddressToNodeId(NetworkInterface nic) {
+ public static byte[] hardwareAddressToNodeId(NetworkInterface nic) throws IllegalStateException {
try {
byte[] hardwareAddress = nic.getHardwareAddress();
final int length = 6;
random.nextBytes(nodeId);
return nodeId;
}
+
+ /**
+ * Force this node id to be identified as no MAC address.
+ *
+ * @see "https://datatracker.ietf.org/doc/html/rfc4122#section-4.5"
+ */
+ static void forceToNoMacAddress(byte[] nodeId, int offset) {
+ assert nodeId != null && offset < nodeId.length;
+ nodeId[offset] = (byte) (nodeId[offset] | 1);
+ }
+
+ /*
+ * SPI UTILITIES
+ */
+ /** Guarantees that a byte array of length 6 will be returned. */
+ static byte[] toNodeIdBytes(byte[] source, int offset) {
+ if (source == null)
+ return null;
+ if (offset < 0 || offset + 6 > source.length)
+ throw new ArrayIndexOutOfBoundsException(offset);
+ byte[] nodeId = new byte[6];
+ System.arraycopy(source, offset, nodeId, 0, 6);
+ return nodeId;
+ }
}
server.stop();
// TODO delete temp dir
started = false;
+ log.debug(() -> "Stopped Jetty server");
} catch (Exception e) {
log.error("Cannot stop Jetty HTTP server", e);
}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" immediate="false" name="CMS State">
- <implementation class="org.argeo.cms.internal.runtime.CmsStateImpl"/>
- <service>
- <provide interface="org.argeo.api.cms.CmsState"/>
- </service>
- <reference bind="setUuidFactory" cardinality="1..1" interface="org.argeo.api.uuid.UuidFactory" name="UuidFactory" policy="static"/>
-</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="UUID Factory">
+ <implementation class="org.argeo.api.uuid.ConcurrentUuidFactory"/>
+ <service>
+ <provide interface="org.argeo.api.uuid.UuidFactory"/>
+ </service>
+ <reference bind="setNodeIdSupplier" cardinality="1..1" interface="org.argeo.api.uuid.NodeIdSupplier" name="NodeIdSupplier" policy="static"/>
+</scr:component>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="UUID Factory">
- <implementation class="org.argeo.cms.acr.CmsUuidFactory"/>
- <service>
- <provide interface="org.argeo.api.uuid.UuidFactory"/>
- </service>
-</scr:component>
Service-Component:\
OSGI-INF/cmsOsgiLogger.xml,\
-OSGI-INF/uuidFactory.xml,\
+OSGI-INF/cmsUuidFactory.xml,\
OSGI-INF/cmsEventBus.xml,\
-OSGI-INF/cmsState.xml,\
OSGI-INF/transactionManager.xml,\
OSGI-INF/cmsUserAdmin.xml,\
OSGI-INF/cmsUserManager.xml,\
+++ /dev/null
-package org.argeo.cms.acr;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.BitSet;
-import java.util.Enumeration;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.uuid.ConcurrentUuidFactory;
-import org.argeo.api.uuid.NodeIdSupplier;
-import org.argeo.api.uuid.UuidBinaryUtils;
-
-public class CmsUuidFactory extends ConcurrentUuidFactory {
- private final static CmsLog log = CmsLog.getLog(CmsUuidFactory.class);
-
- public CmsUuidFactory(byte[] nodeId) {
- super(0, nodeId);
- assert createTimeUUID().node() == BitSet.valueOf(toNodeIdBytes(nodeId, 0)).toLongArray()[0];
- }
-
- public CmsUuidFactory() {
- this(getIpBytes());
- }
-
- /** Returns an SHA1 digest of one of the IP addresses. */
- protected static byte[] getIpBytes() {
- Enumeration<NetworkInterface> netInterfaces = null;
- try {
- netInterfaces = NetworkInterface.getNetworkInterfaces();
- } catch (SocketException e) {
- throw new IllegalStateException(e);
- }
- if (netInterfaces == null)
- throw new IllegalStateException("No interfaces");
-
- InetAddress selectedIpv6 = null;
- InetAddress selectedIpv4 = null;
- netInterfaces: while (netInterfaces.hasMoreElements()) {
- NetworkInterface netInterface = netInterfaces.nextElement();
- byte[] hardwareAddress = null;
- try {
- hardwareAddress = netInterface.getHardwareAddress();
- if (hardwareAddress != null) {
- // first IPv6
- addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
- InetAddress ip = addr.getAddress();
- if (ip instanceof Inet6Address) {
- Inet6Address ipv6 = (Inet6Address) ip;
- if (ipv6.isAnyLocalAddress() || ipv6.isLinkLocalAddress() || ipv6.isLoopbackAddress())
- continue addr;
- selectedIpv6 = ipv6;
- break netInterfaces;
- }
-
- }
- // then IPv4
- addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
- InetAddress ip = addr.getAddress();
- if (ip instanceof Inet4Address) {
- Inet4Address ipv4 = (Inet4Address) ip;
- if (ipv4.isAnyLocalAddress() || ipv4.isLinkLocalAddress() || ipv4.isLoopbackAddress())
- continue addr;
- selectedIpv4 = ipv4;
- }
-
- }
- }
- } catch (SocketException e) {
- throw new IllegalStateException(e);
- }
- }
- InetAddress selectedIp = selectedIpv6 != null ? selectedIpv6 : selectedIpv4;
- if (selectedIp == null) {
- log.warn("No IP address found, using a random node id for UUID generation");
- return NodeIdSupplier.randomNodeId();
- }
- byte[] digest = sha1(selectedIp.getAddress());
- log.debug("Use IP " + selectedIp + " hashed as " + UuidBinaryUtils.toHexString(digest) + " as node id");
- byte[] nodeId = toNodeIdBytes(digest, 0);
- // marks that this is not based on MAC address
- forceToNoMacAddress(nodeId, 0);
- return nodeId;
- }
-
-}
package org.argeo.cms.internal.osgi;
import java.security.AllPermission;
-import java.util.Dictionary;
-import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsState;
+import org.argeo.api.uuid.NodeIdSupplier;
+import org.argeo.cms.internal.runtime.CmsStateImpl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
* bundle (and only it)
*/
public class CmsActivator implements BundleActivator {
- private final static CmsLog log = CmsLog.getLog(CmsActivator.class);
+// private final static CmsLog log = CmsLog.getLog(CmsActivator.class);
// TODO make it configurable
private boolean hardened = false;
}
void destroy() {
- try {
- bundleContext = null;
-// this.logReaderService = null;
- } catch (Exception e) {
- log.error("CMS activator shutdown failed", e);
- }
-
new GogoShellKiller().start();
}
}
- public static <T> void registerService(Class<T> clss, T service, Dictionary<String, ?> properties) {
- if (bundleContext != null) {
- bundleContext.registerService(clss, service, properties);
- }
-
- }
-
- public static <T> T getService(Class<T> clss) {
+// static <T> void registerService(Class<T> clss, T service, Dictionary<String, ?> properties) {
+// if (bundleContext != null) {
+// bundleContext.registerService(clss, service, properties);
+// }
+//
+// }
+//
+ static <T> T getService(Class<T> clss) {
if (bundleContext != null) {
return bundleContext.getService(bundleContext.getServiceReference(clss));
} else {
@Override
public void start(BundleContext bc) throws Exception {
bundleContext = bc;
-
+ CmsStateImpl cmsState = new CmsStateImpl();
+ cmsState.start();
+ bundleContext.registerService(new String[] { CmsState.class.getName(), NodeIdSupplier.class.getName() },
+ cmsState, null);
init();
}
@Override
public void stop(BundleContext bc) throws Exception {
-
- destroy();
- bundleContext = null;
+ try {
+ destroy();
+ CmsStateImpl cmsState = (CmsStateImpl) getService(CmsState.class);
+ cmsState.stop();
+ } finally {
+ bundleContext = null;
+ }
}
- public static BundleContext getBundleContext() {
+ static BundleContext getBundleContext() {
return bundleContext;
}
+ public static String getFrameworkProperty(String key) {
+ if (bundleContext == null)
+ return null;
+ return getBundleContext().getProperty(key);
+ }
}
public class CmsOsgiLogger implements LogListener {
private final static String WHITEBOARD_PATTERN_PROP = "osgi.http.whiteboard.servlet.pattern";
private final static String CONTEXT_NAME_PROP = "contextName";
-
- private LogReaderService logReaderService;
-
-// /** Internal debug for development purposes. */
-// private static Boolean debug = false;
-
-// private Boolean disabled = false;
-//
-// private String level = null;
-
-// private Level log4jLevel = null;
-
-// private Properties configuration;
-
-// private AppenderImpl appender;
-// private BlockingQueue<LogEvent> events;
-// private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
-
-// private Integer maxLastEventsCount = 10 * 1000;
-//
-// /** Marker to prevent stack overflow */
-// private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
-//
-// @Override
-// protected Boolean initialValue() {
-// return false;
-// }
-// };
-
-// public CmsOsgiLogger(LogReaderService lrs) {
-// }
+ private LogReaderService logReaderService;
public void start() {
if (logReaderService != null) {
while (logEntries.hasMoreElements())
logged(logEntries.nextElement());
logReaderService.addLogListener(this);
-
- // configure log4j watcher
-// String log4jConfiguration = KernelUtils.getFrameworkProp("log4j.configuration");
-// if (log4jConfiguration != null && log4jConfiguration.startsWith("file:")) {
-// if (log4jConfiguration.contains("..")) {
-// if (log4jConfiguration.startsWith("file://"))
-// log4jConfiguration = log4jConfiguration.substring("file://".length());
-// else if (log4jConfiguration.startsWith("file:"))
-// log4jConfiguration = log4jConfiguration.substring("file:".length());
-// }
-// try {
-// Path log4jconfigPath;
-// if (log4jConfiguration.startsWith("file:"))
-// log4jconfigPath = Paths.get(new URI(log4jConfiguration));
-// else
-// log4jconfigPath = Paths.get(log4jConfiguration);
-// Thread log4jConfWatcher = new Log4jConfWatcherThread(log4jconfigPath);
-// log4jConfWatcher.start();
-// } catch (Exception e) {
-// stdErr("Badly formatted log4j configuration URI " + log4jConfiguration + ": " + e.getMessage());
-// }
-// }
}
-// try {
-//// events = new LinkedBlockingQueue<LogEvent>();
-////
-//// // if (layout != null)
-//// // setLayout(layout);
-//// // else
-//// // setLayout(new PatternLayout(pattern));
-////// appender = new AppenderImpl();
-//// reloadConfiguration();
-////// Logger.getRootLogger().addAppender(appender);
-////
-//// logDispatcherThread = new LogDispatcherThread();
-//// logDispatcherThread.start();
-// } catch (Exception e) {
-// throw new IllegalStateException("Cannot initialize log4j");
-// }
}
public void stop() throws Exception {
-// events.clear();
-// events = null;
-// logDispatcherThread.interrupt();
logReaderService.removeLogListener(this);
}
this.logReaderService = logReaderService;
}
-
- //
- // ARGEO LOGGER
- //
-
-// public synchronized void register(ArgeoLogListener listener, Integer numberOfPreviousEvents) {
-// String username = CurrentUser.getUsername();
-// if (username == null)
-// throw new IllegalStateException("Only authenticated users can register a log listener");
-//
-// if (!userListeners.containsKey(username)) {
-// List<ArgeoLogListener> lst = Collections.synchronizedList(new ArrayList<ArgeoLogListener>());
-// userListeners.put(username, lst);
-// }
-// userListeners.get(username).add(listener);
-// List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username, numberOfPreviousEvents);
-// for (LogEvent evt : lastEvents)
-// dispatchEvent(listener, evt);
-// }
-//
-// public synchronized void registerForAll(ArgeoLogListener listener, Integer numberOfPreviousEvents,
-// boolean everything) {
-// if (everything)
-// everythingListeners.add(listener);
-// else
-// allUsersListeners.add(listener);
-// List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(null, numberOfPreviousEvents);
-// for (LogEvent evt : lastEvents)
-// if (everything || evt.getUsername() != null)
-// dispatchEvent(listener, evt);
-// }
-//
-// public synchronized void unregister(ArgeoLogListener listener) {
-// String username = CurrentUser.getUsername();
-// if (username == null)// FIXME
-// return;
-// if (!userListeners.containsKey(username))
-// throw new IllegalStateException("No user listeners " + listener + " registered for user " + username);
-// if (!userListeners.get(username).contains(listener))
-// throw new IllegalStateException("No user listeners " + listener + " registered for user " + username);
-// userListeners.get(username).remove(listener);
-// if (userListeners.get(username).isEmpty())
-// userListeners.remove(username);
-//
-// }
-//
-// public synchronized void unregisterForAll(ArgeoLogListener listener) {
-// everythingListeners.remove(listener);
-// allUsersListeners.remove(listener);
-// }
-
-// /** For development purpose, since using regular logging is not easy here */
-// private static void stdOut(Object obj) {
-// System.out.println(obj);
-// }
-//
-// private static void stdErr(Object obj) {
-// System.err.println(obj);
-// }
-//
-// private static void debug(Object obj) {
-// if (debug)
-// System.out.println(obj);
-// }
-//
-// private static boolean isInternalDebugEnabled() {
-// return debug;
-// }
-
- // public void setPattern(String pattern) {
- // this.pattern = pattern;
- // }
-
-// public void setDisabled(Boolean disabled) {
-// this.disabled = disabled;
-// }
-//
-// public void setLevel(String level) {
-// this.level = level;
-// }
-
-// public void setConfiguration(Properties configuration) {
-// this.configuration = configuration;
-// }
-//
-// public void updateConfiguration(Properties configuration) {
-// setConfiguration(configuration);
-// reloadConfiguration();
-// }
-//
-// public Properties getConfiguration() {
-// return configuration;
-// }
-//
-// /**
-// * Reloads configuration (if the configuration {@link Properties} is set)
-// */
-// protected void reloadConfiguration() {
-// if (configuration != null) {
-//// LogManager.resetConfiguration();
-//// PropertyConfigurator.configure(configuration);
-// }
-// }
-
-// protected synchronized void processLoggingEvent(LogEvent event) {
-// if (disabled)
-// return;
-//
-// if (dispatching.get())
-// return;
-//
-// if (level != null && !level.trim().equals("")) {
-//// if (log4jLevel == null || !log4jLevel.toString().equals(level))
-//// try {
-//// log4jLevel = Level.toLevel(level);
-//// } catch (Exception e) {
-//// System.err.println("Log4j level could not be set for level '" + level + "', resetting it to null.");
-//// e.printStackTrace();
-//// level = null;
-//// }
-////
-//// if (log4jLevel != null && !event.getLoggingEvent().getLevel().isGreaterOrEqual(log4jLevel)) {
-//// return;
-//// }
-// }
-//
-//// try {
-//// // admin listeners
-//// Iterator<ArgeoLogListener> everythingIt = everythingListeners.iterator();
-//// while (everythingIt.hasNext())
-//// dispatchEvent(everythingIt.next(), event);
-////
-//// if (event.getUsername() != null) {
-//// Iterator<ArgeoLogListener> allUsersIt = allUsersListeners.iterator();
-//// while (allUsersIt.hasNext())
-//// dispatchEvent(allUsersIt.next(), event);
-////
-//// if (userListeners.containsKey(event.getUsername())) {
-//// Iterator<ArgeoLogListener> userIt = userListeners.get(event.getUsername()).iterator();
-//// while (userIt.hasNext())
-//// dispatchEvent(userIt.next(), event);
-//// }
-//// }
-//// } catch (Exception e) {
-//// stdOut("Cannot process logging event");
-//// e.printStackTrace();
-//// }
-// }
-
-// protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
-//// LoggingEvent event = evt.getLoggingEvent();
-//// logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event.getLevel().toString(),
-//// event.getLoggerName(), event.getThreadName(), event.getMessage(), event.getThrowableStrRep());
-// }
-
-// private class AppenderImpl { // extends AppenderSkeleton {
-// public boolean requiresLayout() {
-// return false;
-// }
-//
-// public void close() {
-// }
-//
-//// @Override
-//// protected void append(LoggingEvent event) {
-//// if (events != null) {
-//// try {
-//// String username = CurrentUser.getUsername();
-//// events.put(new LogEvent(username, event));
-//// } catch (InterruptedException e) {
-//// // silent
-//// }
-//// }
-//// }
-//
-// }
-
-// private class LogDispatcherThread extends Thread {
-// /** encapsulated in order to simplify concurrency management */
-// private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
-//
-// public LogDispatcherThread() {
-// super("Argeo Logging Dispatcher Thread");
-// }
-//
-// public void run() {
-// while (events != null) {
-// try {
-// LogEvent loggingEvent = events.take();
-// processLoggingEvent(loggingEvent);
-// addLastEvent(loggingEvent);
-// } catch (InterruptedException e) {
-// if (events == null)
-// return;
-// }
-// }
-// }
-//
-// protected synchronized void addLastEvent(LogEvent loggingEvent) {
-// if (lastEvents.size() >= maxLastEventsCount)
-// lastEvents.poll();
-// lastEvents.add(loggingEvent);
-// }
-//
-// public synchronized List<LogEvent> getLastEvents(String username, Integer maxCount) {
-// LinkedList<LogEvent> evts = new LinkedList<LogEvent>();
-// ListIterator<LogEvent> it = lastEvents.listIterator(lastEvents.size());
-// int count = 0;
-// while (it.hasPrevious() && (count < maxCount)) {
-// LogEvent evt = it.previous();
-// if (username == null || username.equals(evt.getUsername())) {
-// evts.push(evt);
-// count++;
-// }
-// }
-// return evts;
-// }
-// }
-
-// private class LogEvent {
-// private final String username;
-//// private final LoggingEvent loggingEvent;
-//
-// public LogEvent(String username) {
-// super();
-// this.username = username;
-//// this.loggingEvent = loggingEvent;
-// }
-//
-//// @Override
-//// public int hashCode() {
-//// return loggingEvent.hashCode();
-//// }
-////
-//// @Override
-//// public boolean equals(Object obj) {
-//// return loggingEvent.equals(obj);
-//// }
-////
-//// @Override
-//// public String toString() {
-//// return username + "@ " + loggingEvent.toString();
-//// }
-//
-// public String getUsername() {
-// return username;
-// }
-//
-//// public LoggingEvent getLoggingEvent() {
-//// return loggingEvent;
-//// }
-//
-// }
-//
-// private class Log4jConfWatcherThread extends Thread {
-// private Path log4jConfigurationPath;
-//
-// public Log4jConfWatcherThread(Path log4jConfigurationPath) {
-// super("Log4j Configuration Watcher");
-// try {
-// this.log4jConfigurationPath = log4jConfigurationPath.toRealPath();
-// } catch (IOException e) {
-// this.log4jConfigurationPath = log4jConfigurationPath.toAbsolutePath();
-// stdOut("Cannot determine real path for " + log4jConfigurationPath + ": " + e.getMessage());
-// }
-// }
-//
-// public void run() {
-// Path parentDir = log4jConfigurationPath.getParent();
-// try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
-// parentDir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
-// WatchKey wk;
-// watching: while ((wk = watchService.take()) != null) {
-// for (WatchEvent<?> event : wk.pollEvents()) {
-// final Path changed = (Path) event.context();
-// if (log4jConfigurationPath.equals(parentDir.resolve(changed))) {
-// if (isInternalDebugEnabled())
-// debug(log4jConfigurationPath + " has changed, reloading.");
-//// PropertyConfigurator.configure(log4jConfigurationPath.toUri().toURL());
-// }
-// }
-// // reset the key
-// boolean valid = wk.reset();
-// if (!valid) {
-// break watching;
-// }
-// }
-// } catch (IOException | InterruptedException e) {
-// stdErr("Log4j configuration watcher failed: " + e.getMessage());
-// }
-// }
-// }
}
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.Reader;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.CmsState;
-import org.argeo.api.uuid.UuidFactory;
+import org.argeo.api.uuid.NodeIdSupplier;
+import org.argeo.api.uuid.UuidBinaryUtils;
import org.argeo.cms.CmsDeployProperty;
import org.argeo.cms.auth.ident.IdentClient;
+import org.argeo.cms.util.DigestUtils;
import org.argeo.cms.util.FsUtils;
import org.argeo.cms.util.OS;
/**
* Implementation of a {@link CmsState}, initialising the required services.
*/
-public class CmsStateImpl implements CmsState {
+public class CmsStateImpl implements CmsState, NodeIdSupplier {
private final static CmsLog log = CmsLog.getLog(CmsStateImpl.class);
// REFERENCES
private UUID uuid;
// private final boolean cleanState;
private String hostname;
+ private InetAddress inetAddress;
- private UuidFactory uuidFactory;
+// private UuidFactory uuidFactory;
private final Map<CmsDeployProperty, String> deployPropertyDefaults;
log.trace("CMS State started");
String frameworkUuid = KernelUtils.getFrameworkProp(KernelUtils.OSGI_FRAMEWORK_UUID);
- this.uuid = frameworkUuid != null ? UUID.fromString(frameworkUuid) : uuidFactory.timeUUID();
+ this.uuid = frameworkUuid != null ? UUID.fromString(frameworkUuid) : UUID.randomUUID();
// hostname
this.hostname = getDeployProperty(CmsDeployProperty.HOST);
final String LOCALHOST_IP = "::1";
ForkJoinTask<String> hostnameFJT = ForkJoinPool.commonPool().submit(() -> {
try {
- String hostname = InetAddress.getLocalHost().getHostName();
+ this.inetAddress = InetAddress.getLocalHost();
+ String hostname = this.inetAddress.getHostName();
return hostname;
} catch (UnknownHostException e) {
throw new IllegalStateException("Cannot get local hostname", e);
this.hostname = LOCALHOST_IP;
log.warn("Could not get local hostname, using " + this.hostname);
}
+ } else {
+ InetAddress[] addresses = InetAddress.getAllByName(this.hostname);
+ InetAddress selectedAddr = null;
+ addresses: for (InetAddress addr : addresses) {
+ if (selectedAddr == null)
+ selectedAddr = addr;
+ if (selectedAddr instanceof Inet6Address)
+ break addresses;
+ }
+ this.inetAddress = selectedAddr;
}
availableSince = System.currentTimeMillis();
}
}
}
- log.debug("## CMS starting... (" + uuid + ")\n" + sb + "\n");
+ log.debug("## CMS starting on " + hostname + " ... (" + uuid + ")\n" + sb + "\n");
}
if (log.isTraceEnabled()) {
} catch (RuntimeException | IOException e) {
log.error("## FATAL: CMS state failed", e);
+ throw new IllegalStateException(e);
}
}
return availableSince;
}
+ /*
+ * NodeID supplier
+ */
+
+ @Override
+ public Long get() {
+ return NodeIdSupplier.toNodeIdBase(getIpBytes());
+ }
+
+ /** Returns an SHA1 digest of one of the IP addresses. */
+ protected byte[] getIpBytes() {
+// Enumeration<NetworkInterface> netInterfaces = null;
+// try {
+// netInterfaces = NetworkInterface.getNetworkInterfaces();
+// } catch (SocketException e) {
+// throw new IllegalStateException(e);
+// }
+//
+// InetAddress selectedIpv6 = null;
+// InetAddress selectedIpv4 = null;
+// if (netInterfaces != null) {
+// netInterfaces: while (netInterfaces.hasMoreElements()) {
+// NetworkInterface netInterface = netInterfaces.nextElement();
+// byte[] hardwareAddress = null;
+// try {
+// hardwareAddress = netInterface.getHardwareAddress();
+// if (hardwareAddress != null) {
+// // first IPv6
+// addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
+// InetAddress ip = addr.getAddress();
+// if (ip instanceof Inet6Address) {
+// Inet6Address ipv6 = (Inet6Address) ip;
+// if (ipv6.isAnyLocalAddress() || ipv6.isLinkLocalAddress() || ipv6.isLoopbackAddress())
+// continue addr;
+// selectedIpv6 = ipv6;
+// break netInterfaces;
+// }
+//
+// }
+// // then IPv4
+// addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
+// InetAddress ip = addr.getAddress();
+// if (ip instanceof Inet4Address) {
+// Inet4Address ipv4 = (Inet4Address) ip;
+// if (ipv4.isAnyLocalAddress() || ipv4.isLinkLocalAddress() || ipv4.isLoopbackAddress())
+// continue addr;
+// selectedIpv4 = ipv4;
+// // we keep searching for IPv6
+// }
+//
+// }
+// }
+// } catch (SocketException e) {
+// throw new IllegalStateException(e);
+// }
+// }
+// }
+// InetAddress selectedIp = selectedIpv6 != null ? selectedIpv6 : selectedIpv4;
+ if (this.inetAddress.isLoopbackAddress()) {
+ log.warn("No IP address found, using a random node id for UUID generation");
+ return NodeIdSupplier.randomNodeId();
+ }
+ InetAddress selectedIp = this.inetAddress;
+ byte[] digest = DigestUtils.sha1(selectedIp.getAddress());
+ log.debug("Use IP " + selectedIp + " hashed as " + UuidBinaryUtils.toHexString(digest) + " as node id");
+ byte[] nodeId = NodeIdSupplier.toNodeIdBytes(digest, 0);
+ // marks that this is not based on MAC address
+ NodeIdSupplier.forceToNoMacAddress(nodeId, 0);
+ return nodeId;
+ }
+
/*
* ACCESSORS
*/
return uuid;
}
- public void setUuidFactory(UuidFactory uuidFactory) {
- this.uuidFactory = uuidFactory;
- }
+// public void setUuidFactory(UuidFactory uuidFactory) {
+// this.uuidFactory = uuidFactory;
+// }
public String getHostname() {
return hostname;
// TODO make passphrase more configurable
return new IdentClient(remoteAddr);
}
+
}
--- /dev/null
+package org.argeo.cms.internal.runtime;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.BitSet;
+import java.util.Enumeration;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.uuid.ConcurrentUuidFactory;
+import org.argeo.api.uuid.NodeIdSupplier;
+import org.argeo.api.uuid.UuidBinaryUtils;
+
+@Deprecated
+class CmsUuidFactory extends ConcurrentUuidFactory {
+ private final static CmsLog log = CmsLog.getLog(CmsUuidFactory.class);
+
+ public CmsUuidFactory(byte[] nodeId) {
+ super(0, nodeId);
+ assert createTimeUUID().node() == BitSet.valueOf(NodeIdSupplier.toNodeIdBytes(nodeId, 0)).toLongArray()[0];
+ }
+
+ public CmsUuidFactory() {
+ this(getIpBytes());
+ }
+
+ /** Returns an SHA1 digest of one of the IP addresses. */
+ protected static byte[] getIpBytes() {
+ Enumeration<NetworkInterface> netInterfaces = null;
+ try {
+ netInterfaces = NetworkInterface.getNetworkInterfaces();
+ } catch (SocketException e) {
+ throw new IllegalStateException(e);
+ }
+
+ InetAddress selectedIpv6 = null;
+ InetAddress selectedIpv4 = null;
+ if (netInterfaces != null) {
+ netInterfaces: while (netInterfaces.hasMoreElements()) {
+ NetworkInterface netInterface = netInterfaces.nextElement();
+ byte[] hardwareAddress = null;
+ try {
+ hardwareAddress = netInterface.getHardwareAddress();
+ if (hardwareAddress != null) {
+ // first IPv6
+ addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
+ InetAddress ip = addr.getAddress();
+ if (ip instanceof Inet6Address) {
+ Inet6Address ipv6 = (Inet6Address) ip;
+ if (ipv6.isAnyLocalAddress() || ipv6.isLinkLocalAddress() || ipv6.isLoopbackAddress())
+ continue addr;
+ selectedIpv6 = ipv6;
+ break netInterfaces;
+ }
+
+ }
+ // then IPv4
+ addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
+ InetAddress ip = addr.getAddress();
+ if (ip instanceof Inet4Address) {
+ Inet4Address ipv4 = (Inet4Address) ip;
+ if (ipv4.isAnyLocalAddress() || ipv4.isLinkLocalAddress() || ipv4.isLoopbackAddress())
+ continue addr;
+ selectedIpv4 = ipv4;
+ // we keep searching for IPv6
+ }
+
+ }
+ }
+ } catch (SocketException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+ InetAddress selectedIp = selectedIpv6 != null ? selectedIpv6 : selectedIpv4;
+ if (selectedIp == null) {
+ log.warn("No IP address found, using a random node id for UUID generation");
+ return NodeIdSupplier.randomNodeId();
+ }
+ byte[] digest = sha1(selectedIp.getAddress());
+ log.debug("Use IP " + selectedIp + " hashed as " + UuidBinaryUtils.toHexString(digest) + " as node id");
+ byte[] nodeId = NodeIdSupplier.toNodeIdBytes(digest, 0);
+ // marks that this is not based on MAC address
+ NodeIdSupplier.forceToNoMacAddress(nodeId, 0);
+ return nodeId;
+ }
+}
static String getFrameworkProp(String key, String def) {
String value;
- if (CmsActivator.getBundleContext() != null)
- value = CmsActivator.getBundleContext().getProperty(key);
- else
+ value = CmsActivator.getFrameworkProperty(key);
+ if (value == null)
value = System.getProperty(key);
if (value == null)
return def;
import org.argeo.api.register.Component;
import org.argeo.api.register.ComponentRegister;
import org.argeo.api.register.SimpleRegister;
+import org.argeo.api.uuid.ConcurrentUuidFactory;
+import org.argeo.api.uuid.NodeIdSupplier;
import org.argeo.api.uuid.UuidFactory;
-import org.argeo.cms.acr.CmsUuidFactory;
import org.argeo.cms.internal.runtime.CmsContextImpl;
import org.argeo.cms.internal.runtime.CmsDeploymentImpl;
import org.argeo.cms.internal.runtime.CmsStateImpl;
private CompletableFuture<Void> stopped = new CompletableFuture<Void>();
public void start() {
- // UID factory
- CmsUuidFactory uuidFactory = new CmsUuidFactory();
- Component<CmsUuidFactory> uuidFactoryC = new Component.Builder<>(uuidFactory) //
- .addType(UuidFactory.class) //
- .build(register);
-
// CMS State
CmsStateImpl cmsState = new CmsStateImpl();
Component<CmsStateImpl> cmsStateC = new Component.Builder<>(cmsState) //
.addType(CmsState.class) //
+ .addType(NodeIdSupplier.class) //
.addActivation(cmsState::start) //
.addDeactivation(cmsState::stop) //
- .addDependency(uuidFactoryC.getType(UuidFactory.class), cmsState::setUuidFactory, null) //
+ .build(register);
+
+ // UID factory
+ ConcurrentUuidFactory uuidFactory = new ConcurrentUuidFactory();
+ Component<ConcurrentUuidFactory> uuidFactoryC = new Component.Builder<>(uuidFactory) //
+ .addType(UuidFactory.class) //
+ .addDependency(cmsStateC.getType(NodeIdSupplier.class), uuidFactory::setNodeIdSupplier, null) //
.build(register);
// Transaction manager
includes, excludes);
source.load();
addSource(source);
- logger.log(INFO, () -> "Registered " + uri + " as source");
+ logger.log(DEBUG, () -> "Registered " + uri + " as source");
// OS specific / native
String localRelPath = A2Contribution.localOsArchRelativePath();
new Hashtable<>(Collections.singletonMap(Constants.SERVICE_PID, "argeo.logging.publisher")));
}
OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
- osgiBoot.bootstrap(config);
+ String frameworkUuuid = bundleContext.getProperty(Constants.FRAMEWORK_UUID);
+ new Thread("OSGi boot framework " + frameworkUuuid) {
+ @Override
+ public void run() {
+ osgiBoot.bootstrap(config);
+ }
+ }.start();
}
public void update() {
public void close() throws Exception {
if (framework == null)
return;
-// Bundle scrBundle = osgiBoot.getBundlesBySymbolicName().get();
-// if (scrBundle != null && scrBundle.getState() > Bundle.RESOLVED) {
-// scrBundle.stop();
-// while (!(scrBundle.getState() <= Bundle.RESOLVED)) {
-// Thread.sleep(500);
+ // TODO make shutdown of dynamic service more robust
+// for (Bundle scrBundle : framework.getBundleContext().getBundles()) {
+// if (scrBundle.getSymbolicName().equals(SYMBOLIC_NAME_FELIX_SCR)) {
+// if (scrBundle.getState() > Bundle.RESOLVED) {
+// scrBundle.stop();
+// while (!(scrBundle.getState() <= Bundle.RESOLVED)) {
+// Thread.sleep(100);
+// }
+// Thread.sleep(500);
+// }
// }
-// Thread.sleep(1000);
// }
- // TODO make shutdown of dynamic service more robust
- for (Bundle scrBundle : framework.getBundleContext().getBundles()) {
- if (scrBundle.getSymbolicName().equals(SYMBOLIC_NAME_FELIX_SCR)) {
- if (scrBundle.getState() > Bundle.RESOLVED) {
- scrBundle.stop();
- while (!(scrBundle.getState() <= Bundle.RESOLVED)) {
- Thread.sleep(100);
- }
- Thread.sleep(100);
- }
- }
- }
-
stop();
waitForStop(CLOSE_TIMEOUT);
framework = null;