X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;ds=sidebyside;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fruntime%2FCmsStateImpl.java;h=2758ba9b191bf08693c37d44ff457f0240622e84;hb=01da06d541cdb4ad614579a37be64b5de900bc20;hp=6921de77abc4b07954907ebde4d2d7f679a2dc31;hpb=b35fe2aebb11e9f4f7f81667a0671211e5b91041;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java index 6921de77a..2758ba9b1 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java @@ -3,9 +3,11 @@ package org.argeo.cms.internal.runtime; 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 java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -23,6 +25,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.StringJoiner; +import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; @@ -35,15 +38,18 @@ import javax.security.auth.login.Configuration; 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.util.FsUtils; +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 @@ -52,8 +58,9 @@ public class CmsStateImpl implements CmsState { private UUID uuid; // private final boolean cleanState; private String hostname; + private InetAddress inetAddress; - private UuidFactory uuidFactory; +// private UuidFactory uuidFactory; private final Map deployPropertyDefaults; @@ -91,19 +98,25 @@ public class CmsStateImpl implements CmsState { } public void start() { -// Runtime.getRuntime().addShutdownHook(new CmsShutdown()); - + Charset defaultCharset = Charset.defaultCharset(); + if (!StandardCharsets.UTF_8.equals(defaultCharset)) + log.error("Default JVM charset is " + defaultCharset + " and not " + StandardCharsets.UTF_8); try { + // First init check + Path privateBase = getDataPath(KernelConstants.DIR_PRIVATE); + if (privateBase != null && !Files.exists(privateBase)) {// first init + firstInit(); + Files.createDirectories(privateBase); + } + initSecurity(); // initArgeoLogger(); if (log.isTraceEnabled()) log.trace("CMS State started"); -// String stateUuidStr = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID); -// this.uuid = UUID.fromString(stateUuidStr); - this.uuid = uuidFactory.timeUUID(); -// this.cleanState = stateUuid.equals(frameworkUuid); + String frameworkUuid = KernelUtils.getFrameworkProp(KernelUtils.OSGI_FRAMEWORK_UUID); + this.uuid = frameworkUuid != null ? UUID.fromString(frameworkUuid) : UUID.randomUUID(); // hostname this.hostname = getDeployProperty(CmsDeployProperty.HOST); @@ -112,7 +125,8 @@ public class CmsStateImpl implements CmsState { final String LOCALHOST_IP = "::1"; ForkJoinTask 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); @@ -124,6 +138,16 @@ public class CmsStateImpl implements CmsState { 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(); @@ -146,23 +170,28 @@ public class CmsStateImpl implements CmsState { } } } - log.debug("## CMS starting... (" + uuid + ")\n" + sb + "\n"); + log.debug("## CMS starting on " + hostname + " ... (" + uuid + ")\n" + sb + "\n"); } - Path privateBase = getDataPath(KernelConstants.DIR_PRIVATE); - if (privateBase != null && !Files.exists(privateBase)) {// first init - firstInit(); - Files.createDirectories(privateBase); + if (log.isTraceEnabled()) { + // print system properties + StringJoiner sb = new StringJoiner("\n"); + for (Object key : new TreeMap<>(System.getProperties()).keySet()) { + sb.add(key + "=" + System.getProperty(key.toString())); + } + log.trace("System properties:\n" + sb + "\n"); + } } catch (RuntimeException | IOException e) { log.error("## FATAL: CMS state failed", e); + throw new IllegalStateException(e); } } private void initSecurity() { // private directory permissions - Path privateDir = KernelUtils.getOsgiInstancePath(KernelConstants.DIR_PRIVATE); + Path privateDir = getDataPath(KernelConstants.DIR_PRIVATE); if (privateDir != null) { // TODO rather check whether we can read and write Set posixPermissions = new HashSet<>(); @@ -172,7 +201,8 @@ public class CmsStateImpl implements CmsState { try { if (!Files.exists(privateDir)) Files.createDirectories(privateDir); - Files.setPosixFilePermissions(privateDir, posixPermissions); + if (!OS.LOCAL.isMSWindows()) + Files.setPosixFilePermissions(privateDir, posixPermissions); } catch (IOException e) { log.error("Cannot set permissions on " + privateDir, e); } @@ -188,8 +218,9 @@ public class CmsStateImpl implements CmsState { // explicitly load JAAS configuration Configuration.getConfiguration(); - boolean initSsl = getDeployProperty(CmsDeployProperty.HTTPS_PORT) != null; - if (initSsl) { + boolean initCertificates = (getDeployProperty(CmsDeployProperty.HTTPS_PORT) != null) + || (getDeployProperty(CmsDeployProperty.SSHD_PORT) != null); + if (initCertificates) { initCertificates(); } } @@ -238,9 +269,6 @@ public class CmsStateImpl implements CmsState { log.error("Cannot trust CA certificate", e); } } - -// if (!Files.exists(keyStorePath)) -// PkiUtils.createSelfSignedKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12); } public void stop() { @@ -248,7 +276,8 @@ public class CmsStateImpl implements CmsState { log.debug("CMS stopping... (" + this.uuid + ")"); long duration = ((System.currentTimeMillis() - availableSince) / 1000) / 60; - log.info("## ARGEO CMS STOPPED after " + (duration / 60) + "h " + (duration % 60) + "min uptime ##"); + log.info("## ARGEO CMS " + uuid + " STOPPED after " + (duration / 60) + "h " + (duration % 60) + + "min uptime ##"); } private void firstInit() throws IOException { @@ -375,11 +404,87 @@ public class CmsStateImpl implements CmsState { return KernelUtils.getOsgiInstancePath(relativePath); } + @Override + public Path getStatePath(String relativePath) { + return KernelUtils.getOsgiConfigurationPath(relativePath); + } + @Override public Long getAvailableSince() { 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 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 */ @@ -388,9 +493,9 @@ public class CmsStateImpl implements CmsState { return uuid; } - public void setUuidFactory(UuidFactory uuidFactory) { - this.uuidFactory = uuidFactory; - } +// public void setUuidFactory(UuidFactory uuidFactory) { +// this.uuidFactory = uuidFactory; +// } public String getHostname() { return hostname; @@ -436,4 +541,5 @@ public class CmsStateImpl implements CmsState { // TODO make passphrase more configurable return new IdentClient(remoteAddr); } + }