/* (c) 2017 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver; import org.geoserver.ows.util.KvpUtils; import org.geoserver.platform.GeoServerExtensions; import org.geotools.util.logging.Logging; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * Holds information about how to identify a geoserver node within a cluster. * <p> * Contains both the node identifier itself, and information about how to style the id * for UI purposes. * </p> */ public class GeoServerNodeData { /** * System property, environment variable, etc... used to specify the node id. */ public static final String GEOSERVER_NODE_OPTS = "GEOSERVER_NODE_OPTS"; static final String DEFAULT_NODE_ID_TEMPLATE = "position:absolute; top:12px; left:12px; right:28px; width:auto; background:$background; padding: 1px; border: 1px solid #0076a1; color:$color; font-weight:bold"; static final Logger LOGGER = Logging.getLogger(GeoServerNodeData.class); final String nodeId; final String nodeIdStyle; public GeoServerNodeData(String nodeId, String nodeIdStyle) { this.nodeId = nodeId; this.nodeIdStyle = nodeIdStyle; } /** * Creates a node data from a format-options style string. */ public static GeoServerNodeData createFromString(String nodeOpts) { String nodeId = null; String nodeIdStyle = null; if (nodeOpts == null) { nodeId = null; nodeIdStyle = null; } else { try { Map<String, String> options = parseProperties(nodeOpts); String id = (String) options.get("id"); if (id != null) { if (id.contains("$host_ip")) { InetAddress address = getLocalHostLANAddress(); id = id.replace("$host_ip", address.getHostAddress()); } else if (id.contains("$host_name")) { InetAddress address = getLocalHostLANAddress(); id = id.replace("$host_name", address.getHostName()); } } nodeId = id; String bgcolor = (String) options.get("background"); if (bgcolor == null) { bgcolor = "#dadada"; } String style = DEFAULT_NODE_ID_TEMPLATE.replace("$background", bgcolor); String color = (String) options.get("color"); if (color == null) { color = "#0076a1"; } nodeIdStyle = style.replace("$color", color); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to parse GEOSERVER_NODE_OPTS, expected syntax is id:<nodeid>;color:<css_color>, but got " + nodeOpts + " instead. Disabling NODE_ID GUI element"); nodeId = null; nodeIdStyle = null; } } return new GeoServerNodeData(nodeId, nodeIdStyle); } /** * Creates the node data from environment variable, system property, etc... define by {@link #GEOSERVER_NODE_OPTS} */ public static GeoServerNodeData createFromEnvironment() { return createFromString(GeoServerExtensions.getProperty(GEOSERVER_NODE_OPTS)); } static InetAddress getLocalHostLANAddress() throws UnknownHostException { try { InetAddress candidateAddress = null; // Iterate all NICs (network interface cards)... for (Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); interfaces .hasMoreElements();) { NetworkInterface ni = (NetworkInterface) interfaces.nextElement(); // each interface can have more than one address for (Enumeration inetAddrs = ni.getInetAddresses(); inetAddrs.hasMoreElements();) { InetAddress inetAddr = (InetAddress) inetAddrs.nextElement(); // we are not interested in loopback if (!inetAddr.isLoopbackAddress()) { if (inetAddr.isSiteLocalAddress()) { return inetAddr; } else if (candidateAddress == null) { candidateAddress = inetAddr; } } } } if (candidateAddress != null) { return candidateAddress; } // Fall back to whatever localhost provides InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); if (jdkSuppliedAddress == null) { throw new UnknownHostException( "The JDK InetAddress.getLocalHost() method unexpectedly returned null."); } return jdkSuppliedAddress; } catch (Exception e) { UnknownHostException unknownHostException = new UnknownHostException( "Failed to determine LAN address"); unknownHostException.initCause(e); throw unknownHostException; } } /** * Parses a format-options like paramter, ; separated, with : as the assignment operator, * key1:value1;key2=value2;..., using backslash as the escape char if needed */ private static Map<String, String> parseProperties(String property) { Map<String, String> properties = new HashMap<String, String>(); List<String> kvps = KvpUtils.escapedTokens(property, ';'); for (String kvp : kvps) { List<String> kv = KvpUtils.escapedTokens(kvp, ':', 2); String key = kv.get(0).toLowerCase(); String value = kv.size() == 1 ? "true" : KvpUtils.unescape(kv.get(1)); properties.put(key, value); } return properties; } /** * The node id. */ public String getId() { return nodeId; } /** * The node id styling. */ public String getIdStyle() { return nodeIdStyle; } }