
org.apache.sling.discovery.oak.TopologyWebConsolePlugin Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.sling.discovery.oak Show documentation
Show all versions of org.apache.sling.discovery.oak Show documentation
Implementation of Apache Sling Discovery based on Jackrabbit Oak using its discovery-lite descriptor for in-cluster view detection and a TopologyView through HTTP POST heartbeats announcing sub-topologies to each other.
/*
* 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.discovery.oak;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.webconsole.AbstractWebConsolePlugin;
import org.apache.felix.webconsole.WebConsoleConstants;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.discovery.ClusterView;
import org.apache.sling.discovery.InstanceDescription;
import org.apache.sling.discovery.InstanceFilter;
import org.apache.sling.discovery.TopologyEvent;
import org.apache.sling.discovery.TopologyEvent.Type;
import org.apache.sling.discovery.TopologyEventListener;
import org.apache.sling.discovery.TopologyView;
import org.apache.sling.discovery.base.commons.ClusterViewService;
import org.apache.sling.discovery.base.connectors.announcement.Announcement;
import org.apache.sling.discovery.base.connectors.announcement.AnnouncementRegistry;
import org.apache.sling.discovery.base.connectors.announcement.CachedAnnouncement;
import org.apache.sling.discovery.base.connectors.ping.ConnectorRegistry;
import org.apache.sling.discovery.base.connectors.ping.TopologyConnectorClientInformation;
import org.apache.sling.discovery.commons.InstancesDiff;
import org.apache.sling.discovery.commons.providers.spi.base.DiscoveryLiteDescriptor;
import org.apache.sling.discovery.commons.providers.spi.base.OakBacklogClusterSyncService;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple webconsole which gives an overview of the topology visible by the
* discovery service
*/
@Component
@Service(value = { TopologyEventListener.class, Servlet.class })
@Properties({
@Property(name=org.osgi.framework.Constants.SERVICE_DESCRIPTION,
value="Apache Sling Web Console Plugin to display Background servlets and ExecutionEngine status"),
@Property(name=WebConsoleConstants.PLUGIN_LABEL, value=TopologyWebConsolePlugin.LABEL),
@Property(name=WebConsoleConstants.PLUGIN_TITLE, value=TopologyWebConsolePlugin.TITLE),
@Property(name="felix.webconsole.category", value="Sling"),
@Property(name="felix.webconsole.configprinter.modes", value={"zip"})
})
@SuppressWarnings("serial")
public class TopologyWebConsolePlugin extends AbstractWebConsolePlugin implements TopologyEventListener {
public static final String LABEL = "topology";
public static final String TITLE = "Topology Management";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/** the truncated log of topology events, filtered by property change types. shown in webconsole **/
private final List propertyChangeLog = new LinkedList();
/** the truncated log of topology events, shown in webconsole **/
private final List topologyLog = new LinkedList();
/** the date format used in the truncated log of topology events **/
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
@Reference
private ClusterViewService clusterViewService;
@Reference
private AnnouncementRegistry announcementRegistry;
@Reference
private ConnectorRegistry connectorRegistry;
@Reference
protected ResourceResolverFactory resourceResolverFactory;
@Reference
private OakBacklogClusterSyncService clusterSyncService;
private TopologyView currentView;
private List discoveryLiteHistory = new LinkedList();
/**
* keeps hold of the last DiscoveryLiteDescriptor that was added
* to the discoveryLiteHistory - in order to de-duplicate as we go
*/
private DiscoveryLiteDescriptor lastDiscoveryLiteDescriptor = null;
@Override
public String getLabel() {
return LABEL;
}
@Override
public String getTitle() {
return TITLE;
}
@Activate
@Override
public void activate(final BundleContext bundleContext) {
super.activate(bundleContext);
}
@Deactivate
@Override
public void deactivate() {
super.deactivate();
}
@Override
protected void renderContent(final HttpServletRequest req, final HttpServletResponse res)
throws ServletException, IOException {
Object rawRoot = req.getAttribute(WebConsoleConstants.ATTR_PLUGIN_ROOT);
if (!(rawRoot instanceof String)) {
throw new ServletException("Illegal attr: "
+ WebConsoleConstants.ATTR_PLUGIN_ROOT);
}
String root = rawRoot.toString();
String pathInfo = req.getRequestURI().substring(root.length());
final PrintWriter pw = res.getWriter();
if (pathInfo.equals("")) {
if ( this.currentView != null ) {
renderOverview(pw, currentView);
} else {
pw.println("No view available
");
pw.println("
");
pw.println("No TOPOLOGY_INIT received yet, therefore no view available yet.");
}
} else {
StringTokenizer st = new StringTokenizer(pathInfo, "/");
final String nodeId = st.nextToken();
renderProperties(pw, req.getContextPath(), nodeId);
}
}
/**
* Render the properties page of a particular instance
*/
private void renderProperties(final PrintWriter pw, final String contextPath, final String nodeId) {
if (logger.isDebugEnabled()) {
logger.debug("renderProperties: nodeId=" + nodeId);
}
final TopologyView tv = this.currentView;
@SuppressWarnings("unchecked")
Set instances = ( tv == null ? (Set)Collections.EMPTY_SET :
tv.findInstances(new InstanceFilter() {
public boolean accept(InstanceDescription instance) {
String slingId = instance.getSlingId();
if (logger.isDebugEnabled()) {
logger.debug("renderProperties/picks: slingId={}", slingId);
}
return (slingId.equals(nodeId));
}
}));
if (instances != null && instances.size() == 1) {
InstanceDescription instance = instances.iterator().next();
pw.println("Properties of " + instance.getSlingId() + ":
");
pw.println("");
pw.println("");
pw.println("");
pw.println("Key ");
pw.println("Value ");
pw.println(" ");
pw.println("");
pw.println("");
boolean odd = true;
for (Iterator> it = instance.getProperties()
.entrySet().iterator(); it.hasNext();) {
Entry entry = it.next();
String oddEven = odd ? "odd" : "even";
odd = !odd;
pw.println("");
pw.println("" + entry.getKey() + " ");
pw.println("" + entry.getValue() + " ");
pw.println(" ");
}
pw.println(" ");
pw.println("
");
}
}
protected ResourceResolver getResourceResolver() throws LoginException {
return resourceResolverFactory.getAdministrativeResourceResolver(null);
}
/**
* Render the overview of the entire topology
*/
private void renderOverview(final PrintWriter pw, final TopologyView topology) {
pw.println("Configuration
");
pw.println("
");
pw.print("Configure Discovery.Oak Service");
pw.println("
");
pw.println("
");
final String changing;
if (!topology.isCurrent()) {
changing = " CHANGING! (the view is no longer current!)";
} else {
changing = "";
}
pw.println("Topology"+changing+"
");
pw.println(" ");
pw.println("");
pw.println("");
pw.println("");
pw.println("Sling id (click for properties) ");
pw.println("ClusterView id ");
pw.println("Local instance ");
pw.println("Leader instance ");
pw.println("In local cluster ");
pw.println("Announced by instance ");
pw.println(" ");
pw.println("");
pw.println("");
Set clusters = topology.getClusterViews();
ClusterView myCluster = topology.getLocalInstance().getClusterView();
boolean odd = true;
renderCluster(pw, myCluster, myCluster, odd, topology.isCurrent());
for (Iterator it = clusters.iterator(); it.hasNext();) {
ClusterView clusterView = it.next();
if (clusterView.equals(myCluster)) {
// skip - I already rendered that
continue;
}
odd = !odd;
renderCluster(pw, clusterView, myCluster, odd, topology.isCurrent());
}
pw.println(" ");
pw.println("
");
pw.println("
");
pw.println("
");
pw.println("Connectors
");
listIncomingTopologyConnectors(pw);
listOutgoingTopologyConnectors(pw);
pw.println("
");
pw.println("Topology Change History
");
pw.println("");
for (Iterator it = topologyLog
.iterator(); it.hasNext();) {
String aLogEntry = it.next();
pw.println(aLogEntry);
}
pw.println("
");
pw.println("
");
pw.println("Property Change History
");
pw.println("");
for (Iterator it = propertyChangeLog
.iterator(); it.hasNext();) {
String aLogEntry = it.next();
pw.println(aLogEntry);
}
pw.println("
");
pw.println("");
pw.println("Oak Discovery-Lite Descriptor History
");
updateDiscoveryLiteHistory();
pw.println("");
for (String discoLiteHistoryEntry : discoveryLiteHistory) {
pw.println(discoLiteHistoryEntry);
}
pw.println("
");
pw.println("
");
pw.println("ClusterSyncService History
");
pw.println("");
for (String syncHistoryEntry : clusterSyncService.getSyncHistory()) {
pw.println(syncHistoryEntry);
}
pw.println("
");
pw.println("
");
}
/**
* Render a particular cluster (into table rows)
*/
private void renderCluster(final PrintWriter pw, final ClusterView renderCluster, final ClusterView localCluster, final boolean odd, final boolean current) {
final Collection announcements = announcementRegistry.listAnnouncementsInSameCluster(localCluster);
for (Iterator it = renderCluster.getInstances()
.iterator(); it.hasNext();) {
final InstanceDescription instanceDescription = it.next();
final boolean inLocalCluster = renderCluster == localCluster;
Announcement parentAnnouncement = null;
for (Iterator it2 = announcements.iterator(); it2
.hasNext();) {
Announcement announcement = it2.next();
for (Iterator it3 = announcement
.listInstances().iterator(); it3.hasNext();) {
InstanceDescription announcedInstance = it3.next();
if (announcedInstance.getSlingId().equals(
instanceDescription.getSlingId())) {
parentAnnouncement = announcement;
break;
}
}
}
final String oddEven = odd ? "odd" : "even";
if (current && (inLocalCluster || (parentAnnouncement!=null))) {
pw.println("");
} else {
pw.println(" ");
}
final boolean isLocal = instanceDescription.isLocal();
final String slingId = instanceDescription.getSlingId();
pw.print("");
if ( isLocal) {
pw.print("");
}
pw.print("");
pw.print(slingId);
pw.print("");
if ( isLocal) {
pw.print("");
}
pw.println(" ");
pw.println(""
+ (instanceDescription.getClusterView() == null ? "null"
: instanceDescription.getClusterView().getId())
+ " ");
pw.println("" + (isLocal ? "true" : "false") + " ");
pw.println(""
+ (instanceDescription.isLeader() ? "true" : "false")
+ " ");
if (inLocalCluster) {
pw.println("local ");
pw.println("n/a ");
} else {
pw.println("remote ");
if (parentAnnouncement != null) {
pw.println("" + parentAnnouncement.getOwnerId()
+ " ");
} else {
pw.println("(changing) ");
}
}
pw.println(" ");
}
}
/**
* Render the outgoing topology connectors - including the header-div and table
*/
private void listOutgoingTopologyConnectors(final PrintWriter pw) {
boolean odd = false;
pw.println(" ");
pw.println("");
pw.println("");
pw.println("");
pw.println("Connector url ");
pw.println("Connected to slingId ");
pw.println("Connector status ");
pw.println("Last heartbeat ");
pw.println("Next heartbeat ");
pw.println("Request encoding ");
pw.println("Response encoding ");
// pw.println("Fallback connector urls ");
pw.println(" ");
pw.println("");
pw.println("");
Collection outgoingConnections = connectorRegistry
.listOutgoingConnectors();
for (Iterator it = outgoingConnections
.iterator(); it.hasNext();) {
TopologyConnectorClientInformation topologyConnectorClient = it
.next();
final String oddEven = odd ? "odd" : "even";
odd = !odd;
final String remoteSlingId = topologyConnectorClient.getRemoteSlingId();
final boolean isConnected = topologyConnectorClient.isConnected() && remoteSlingId != null;
final boolean autoStopped = topologyConnectorClient.isAutoStopped();
final boolean representsLoop = topologyConnectorClient.representsLoop();
if (isConnected || autoStopped || representsLoop) {
pw.println("");
} else {
pw.println(" ");
}
pw.println(""
+ topologyConnectorClient.getConnectorUrl().toString()
+ " ");
if (autoStopped) {
pw.println("auto-stopped ");
pw.println("auto-stopped due to local-loop ");
} else if (isConnected && !representsLoop) {
pw.println("" + remoteSlingId + " ");
pw.println("ok, in use ");
} else if (representsLoop) {
pw.println("" + remoteSlingId + " ");
pw.println("ok, unused (loop or duplicate): standby ");
} else {
final int statusCode = topologyConnectorClient.getStatusCode();
final String statusDetails = topologyConnectorClient.getStatusDetails();
final String tooltipText;
switch(statusCode) {
case HttpServletResponse.SC_UNAUTHORIZED:
tooltipText = HttpServletResponse.SC_UNAUTHORIZED +
": possible setup issue of discovery.oak on target instance, or wrong URL";
break;
case HttpServletResponse.SC_NOT_FOUND:
tooltipText = HttpServletResponse.SC_NOT_FOUND +
": possible white list rejection by target instance";
break;
case -1:
tooltipText = "-1: check error log. possible connection refused.";
break;
default:
tooltipText = null;
}
final String tooltip = tooltipText==null ? "" : (" title=\""+tooltipText+"\"");
pw.println("not connected ");
pw.println("not ok (HTTP Status-Code: "+statusCode+", "+statusDetails+") ");
}
pw.println(""+beautifiedTimeDiff(topologyConnectorClient.getLastPingSent())+" ");
pw.println(""+beautifiedDueTime(topologyConnectorClient.getNextPingDue())+" ");
pw.println(""+topologyConnectorClient.getLastRequestEncoding()+" ");
pw.println(""+topologyConnectorClient.getLastResponseEncoding()+" ");
// //TODO fallback urls are not yet implemented!
// String fallbackConnectorUrls;
// List urls = topologyConnectorClient
// .listFallbackConnectorUrls();
// if (urls == null || urls.size() == 0) {
// fallbackConnectorUrls = "n/a";
// } else {
// fallbackConnectorUrls = "";
// for (Iterator it2 = urls.iterator(); it2.hasNext();) {
// String aFallbackConnectorUrl = it2.next();
// fallbackConnectorUrls = fallbackConnectorUrls
// + aFallbackConnectorUrl + "
";
// }
// }
// pw.println("" + fallbackConnectorUrls + " ");
}
pw.println(" ");
pw.println("
");
}
private String beautifiedDueTime(long secondsDue) {
if (secondsDue<-1) {
return "overdue";
} else if (secondsDue<=0) {
return "now-ish";
} else if (secondsDue==1) {
return "in 1 second";
} else {
int minsDue = (int) (secondsDue / 60);
if (minsDue<5) {
return "in "+secondsDue+" seconds";
} else {
return "in "+minsDue+" minutes";
}
}
}
private String beautifiedTimeDiff(long heartbeatTime) {
final long diff = System.currentTimeMillis() - heartbeatTime;
long seconds = (diff/1000);
if (heartbeatTime<=0) {
return "n/a";
} else if (seconds==0) {
return diff+" millis ago";
} else if (seconds==1) {
return "1 second ago";
} else if (seconds<300) {
// then print seconds
return seconds+" seconds ago";
} else {
// then print seconds
return (seconds/60)+" minute ago";
}
}
/**
* Render the incoming topology connectors - including the header-div and table
*/
private void listIncomingTopologyConnectors(final PrintWriter pw) {
boolean odd = false;
pw.println(" ");
pw.println("");
pw.println("");
pw.println("");
pw.println("Owner slingId ");
pw.println("Server info ");
pw.println("Last heartbeat ");
pw.println("Timeout ");
pw.println(" ");
pw.println("");
pw.println("");
Collection incomingConnections = announcementRegistry.listLocalIncomingAnnouncements();
for (Iterator it = incomingConnections.iterator(); it
.hasNext();) {
CachedAnnouncement incomingCachedAnnouncement = it.next();
Announcement incomingAnnouncement = incomingCachedAnnouncement.getAnnouncement();
String oddEven = odd ? "odd" : "even";
odd = !odd;
pw.println("");
pw.println("" + incomingAnnouncement.getOwnerId() + " ");
if (incomingAnnouncement.getServerInfo() != null) {
pw.println("" + incomingAnnouncement.getServerInfo()
+ " ");
} else {
pw.println("n/a ");
}
pw.println(""+beautifiedTimeDiff(incomingCachedAnnouncement.getLastPing())+" ");
pw.println(""+beautifiedDueTime(incomingCachedAnnouncement.getSecondsUntilTimeout())+" ");
pw.println(" ");
}
pw.println(" ");
pw.println("
");
pw.println("
");
pw.println("
");
}
/**
* keep a truncated history of the log events for information purpose (to be shown in the webconsole)
*/
public void handleTopologyEvent(final TopologyEvent event) {
if (event.getType() == Type.PROPERTIES_CHANGED) {
this.currentView = event.getNewView();
StringBuilder sb = new StringBuilder();
InstancesDiff instanceDiff = new InstancesDiff(event.getOldView(), event.getNewView());
// there shouldn't be any instances added, but for paranoia reason:
Collection added = instanceDiff.added().get();
if (!added.isEmpty()) {
sb.append("instances were added:");
for (InstanceDescription instance : added) {
sb.append(" ");
sb.append(instance.getSlingId());
}
sb.append(".");
}
// there shouldn't be any instances removed as well, but again for paranoia reason:
Collection removed = instanceDiff.removed().get();
if (!removed.isEmpty()) {
sb.append("instances were removed:");
for (InstanceDescription instance : added) {
sb.append(" ");
sb.append(instance.getSlingId());
}
sb.append(".");
}
Set newInstances = event.getNewView()
.getInstances();
for (Iterator it = newInstances.iterator(); it
.hasNext();) {
final InstanceDescription newInstanceDescription = it.next();
InstanceDescription oldInstanceDescription = findInstance(
event.getOldView(), newInstanceDescription.getSlingId());
if (oldInstanceDescription == null) {
logger.error("handleTopologyEvent: got a property changed but did not find instance "
+ newInstanceDescription
+ " in oldview.. event="
+ event);
sb.append("did not find instance in old view: " + newInstanceDescription.getSlingId() + ".");
continue;
}
Map oldProps = oldInstanceDescription
.getProperties();
Map newProps = newInstanceDescription
.getProperties();
StringBuilder diff = diff(oldProps, newProps);
if (diff.length() > 0) {
if (sb.length() != 0) {
sb.append(", ");
}
sb.append("on instance "
+ newInstanceDescription.getSlingId() + (newInstanceDescription.isLeader() ? " [isLeader]" : "")
+ ": " + diff + ". ");
}
}
addEventLog(event.getType(), "details: "+sb.toString());
} else if (event.getType() == Type.TOPOLOGY_INIT) {
this.currentView = event.getNewView();
StringBuilder details = new StringBuilder();
for (Iterator it = event.getNewView()
.getInstances().iterator(); it.hasNext();) {
InstanceDescription newInstance = it.next();
if (details.length() != 0) {
details.append(", ");
}
details.append(newInstance.getSlingId());
if (newInstance.isLeader()) {
details.append(" [isLeader]");
}
}
addEventLog(event.getType(),
"view: " + shortViewInfo(event.getNewView()) + ". "
+ details);
} else if (event.getType() == Type.TOPOLOGY_CHANGING) {
this.currentView = event.getOldView();
addEventLog(event.getType(),
"old view: " + shortViewInfo(event.getOldView()));
} else {
this.currentView = event.getNewView();
if (event.getOldView() == null) {
addEventLog(event.getType(),
"new view: " + shortViewInfo(event.getNewView()));
} else {
StringBuilder details = new StringBuilder();
for (Iterator it = event.getNewView()
.getInstances().iterator(); it.hasNext();) {
InstanceDescription newInstance = it.next();
if (findInstance(event.getOldView(),
newInstance.getSlingId()) == null) {
if (details.length() != 0) {
details.append(", ");
}
details.append(newInstance.getSlingId() + " joined");
}
}
for (Iterator it = event.getOldView()
.getInstances().iterator(); it.hasNext();) {
InstanceDescription oldInstance = it.next();
if (findInstance(event.getNewView(),
oldInstance.getSlingId()) == null) {
if (details.length() != 0) {
details.append(", ");
}
details.append(oldInstance.getSlingId() + " left");
}
}
final InstanceDescription li = event.getNewView().getLocalInstance();
if (li!=null) {
ClusterView clusterView = li.getClusterView();
if (clusterView!=null) {
final InstanceDescription leader = clusterView.getLeader();
if (leader!=null) {
if (details.length() !=0) {
details.append(", ");
}
details.append("[isLeader: "+leader.getSlingId()+"]");
}
}
}
addEventLog(
event.getType(),
"old view: " + shortViewInfo(event.getOldView())
+ ", new view: "
+ shortViewInfo(event.getNewView()) + ". "
+ details);
}
}
updateDiscoveryLiteHistory();
}
/**
* find a particular instance in the topology
*/
private InstanceDescription findInstance(final TopologyView view,
final String slingId) {
Set foundInstances = view
.findInstances(new InstanceFilter() {
public boolean accept(InstanceDescription instance) {
return instance.getSlingId().equals(slingId);
}
});
if (foundInstances.size() == 1) {
return foundInstances.iterator().next();
} else {
return null;
}
}
/**
* add a log entry and truncate the log entries if necessary
*/
private synchronized void addEventLog(final Type type, final String info) {
final String logEntry = getCurrentDateFormatted() + ": " + type + ". " + info;
if (type == Type.PROPERTIES_CHANGED) {
propertyChangeLog.add(logEntry);
while (propertyChangeLog.size() > 12) {
propertyChangeLog.remove(0);
}
} else {
topologyLog.add(logEntry);
while (topologyLog.size() > 12) {
topologyLog.remove(0);
}
}
}
/**
* if there's any change add a discoveryLite descriptor entry to the history, truncating if necessary
*/
private synchronized void updateDiscoveryLiteHistory() {
ResourceResolver resourceResolver = null;
try{
resourceResolver = getResourceResolver();
DiscoveryLiteDescriptor descriptor =
DiscoveryLiteDescriptor.getDescriptorFrom(resourceResolver);
if (lastDiscoveryLiteDescriptor!=null &&
descriptor.getDescriptorStr().equals(lastDiscoveryLiteDescriptor.getDescriptorStr())) {
// de-duplication - then there's nothing to update
return;
}
final String logEntry = getCurrentDateFormatted() + ": " + descriptor.getDescriptorStr();
lastDiscoveryLiteDescriptor = descriptor;
discoveryLiteHistory.add(logEntry);
while (discoveryLiteHistory.size() > 12) {
discoveryLiteHistory.remove(0);
}
} catch(Exception e) {
logger.error("addDiscoveryLiteHistoryEntry: Exception: "+e, e);
} finally {
if (resourceResolver != null) {
resourceResolver.close();
}
}
}
/**
* compile a short information string of the topology, including
* number of clusters and instances
*/
private String shortViewInfo(final TopologyView view) {
int clusters = view.getClusterViews().size();
int instances = view.getInstances().size();
return ((clusters == 1) ? "1 cluster" : clusters + " clusters") + ", "
+ ((instances == 1) ? "1 instance" : instances + " instances");
}
/**
* calculate the difference between two sets of properties
*/
private StringBuilder diff(final Map oldProps,
final Map newProps) {
final Set oldKeys = new HashSet(oldProps.keySet());
final Set newKeys = new HashSet(newProps.keySet());
StringBuilder sb = new StringBuilder();
for (Iterator it = oldKeys.iterator(); it.hasNext();) {
String oldKey = it.next();
if (newKeys.contains(oldKey)) {
if (oldProps.get(oldKey).equals(newProps.get(oldKey))) {
// perfect
} else {
sb.append("(" + oldKey + " changed from "
+ oldProps.get(oldKey) + " to "
+ newProps.get(oldKey) + ")");
}
newKeys.remove(oldKey);
} else {
sb.append("(" + oldKey + " was removed)");
}
it.remove();
}
for (Iterator it = newKeys.iterator(); it.hasNext();) {
String newKey = it.next();
sb.append("(" + newKey + " was added)");
}
return sb;
}
public void printConfiguration( final PrintWriter pw ) {
final TopologyView topology = this.currentView;
pw.println(TITLE);
pw.println("---------------------------------------");
pw.println();
if ( topology == null ) {
pw.println("No topology available yet!");
return;
}
pw.print("Topology");
if (!topology.isCurrent()) {
pw.print(" CHANGING! (the view is no longer current!)");
}
pw.println();
pw.println();
final Set clusters = topology.getClusterViews();
final ClusterView myCluster = topology.getLocalInstance().getClusterView();
printCluster(pw, myCluster, myCluster);
for (Iterator it = clusters.iterator(); it.hasNext();) {
ClusterView clusterView = it.next();
if (clusterView.equals(myCluster)) {
// skip - I already rendered that
continue;
}
printCluster(pw, clusterView, myCluster);
}
pw.println();
pw.println();
final Collection incomingConnections = announcementRegistry.listLocalIncomingAnnouncements();
if ( incomingConnections.size() > 0 ) {
pw.println("Incoming topology connectors");
pw.println("---------------------------------------");
for(final CachedAnnouncement incomingCachedAnnouncement : incomingConnections) {
Announcement incomingAnnouncement = incomingCachedAnnouncement.getAnnouncement();
pw.print("Owner Sling Id : ");
pw.print(incomingAnnouncement.getOwnerId());
pw.println();
if (incomingAnnouncement.getServerInfo() != null) {
pw.print("Server Info : ");
pw.print(incomingAnnouncement.getServerInfo());
pw.println();
}
pw.println("Last heartbeat received : "+beautifiedTimeDiff(incomingCachedAnnouncement.getLastPing()));
pw.println("Timeout : "+beautifiedDueTime(incomingCachedAnnouncement.getSecondsUntilTimeout()));
pw.println();
}
pw.println();
pw.println();
}
final Collection outgoingConnections = connectorRegistry.listOutgoingConnectors();
if ( outgoingConnections.size() > 0 ) {
pw.println("Outgoing topology connectors");
pw.println("---------------------------------------");
for(final TopologyConnectorClientInformation topologyConnectorClient : outgoingConnections) {
final String remoteSlingId = topologyConnectorClient.getRemoteSlingId();
final boolean autoStopped = topologyConnectorClient.isAutoStopped();
final boolean isConnected = topologyConnectorClient.isConnected() && remoteSlingId != null;
pw.print("Connector URL : ");
pw.print(topologyConnectorClient.getConnectorUrl());
pw.println();
if (autoStopped) {
pw.println("Conncted to Sling Id : auto-stopped");
pw.println("Connector status : auto-stopped due to local-loop");
} else if (isConnected && !topologyConnectorClient.representsLoop()) {
pw.print("Connected to Sling Id : ");
pw.println(remoteSlingId);
pw.println("Connector status : ok, in use");
} else if (topologyConnectorClient.representsLoop()) {
pw.print("Connected to Sling Id : ");
pw.println(remoteSlingId);
pw.println("Connector status : ok, unused (loop or duplicate): standby");
} else {
final int statusCode = topologyConnectorClient.getStatusCode();
final String statusDetails = topologyConnectorClient.getStatusDetails();
final String tooltipText;
switch(statusCode) {
case HttpServletResponse.SC_UNAUTHORIZED:
tooltipText = HttpServletResponse.SC_UNAUTHORIZED +
": possible setup issue of discovery.oak on target instance, or wrong URL";
break;
case HttpServletResponse.SC_NOT_FOUND:
tooltipText = HttpServletResponse.SC_NOT_FOUND +
": possible white list rejection by target instance";
break;
case -1:
tooltipText = "-1: check error log. possible connection refused.";
break;
default:
tooltipText = null;
}
pw.println("Connected to Sling Id : not connected");
pw.print("Connector status : not ok");
if ( tooltipText != null ) {
pw.print(" (");
pw.print(tooltipText);
pw.print(")");
}
pw.print(" (HTTP StatusCode: "+statusCode+", "+statusDetails+")");
pw.println();
pw.println("Last heartbeat sent : "+beautifiedTimeDiff(topologyConnectorClient.getLastPingSent()));
pw.println("Next heartbeat due : "+beautifiedDueTime(topologyConnectorClient.getNextPingDue()));
}
pw.println();
}
pw.println();
pw.println();
}
if ( topologyLog.size() > 0 ) {
pw.println("Topology Change History");
pw.println("---------------------------------------");
for(final String aLogEntry : topologyLog) {
pw.println(aLogEntry);
}
pw.println();
pw.println();
}
if ( propertyChangeLog.size() > 0 ) {
pw.println("Property Change History");
pw.println("---------------------------------------");
for(final String aLogEntry : propertyChangeLog) {
pw.println(aLogEntry);
}
pw.println();
}
pw.println("Oak Discovery-Lite Descriptor History");
pw.println("---------------------------------------");
updateDiscoveryLiteHistory();
for (String discoLiteHistoryEntry : discoveryLiteHistory) {
pw.println(discoLiteHistoryEntry);
}
pw.println();
pw.println();
pw.println("ClusterSyncService History");
pw.println("---------------------------------------");
for (String syncHistoryEntry : clusterSyncService.getSyncHistory()) {
pw.println(syncHistoryEntry);
}
pw.println();
pw.println();
}
private String getCurrentDateFormatted() {
return sdf.format(Calendar.getInstance().getTime());
}
/**
* Render a particular cluster
*/
private void printCluster(final PrintWriter pw, final ClusterView renderCluster, final ClusterView localCluster) {
final Collection announcements = announcementRegistry.listAnnouncementsInSameCluster(localCluster);
for(final InstanceDescription instanceDescription : renderCluster.getInstances() ) {
final boolean inLocalCluster = renderCluster == localCluster;
Announcement parentAnnouncement = null;
for (Iterator it2 = announcements.iterator(); it2
.hasNext();) {
Announcement announcement = it2.next();
for (Iterator it3 = announcement
.listInstances().iterator(); it3.hasNext();) {
InstanceDescription announcedInstance = it3.next();
if (announcedInstance.getSlingId().equals(
instanceDescription.getSlingId())) {
parentAnnouncement = announcement;
break;
}
}
}
final boolean isLocal = instanceDescription.isLocal();
final String slingId = instanceDescription.getSlingId();
pw.print("Sling ID : ");
pw.print(slingId);
pw.println();
pw.print("Cluster View ID : ");
pw.print(instanceDescription.getClusterView() == null ? "null"
: instanceDescription.getClusterView().getId());
pw.println();
pw.print("Local instance : ");
pw.print(isLocal);
pw.println();
pw.print("Leader instance : ");
pw.print(instanceDescription.isLeader());
pw.println();
pw.print("In local cluster : ");
if (inLocalCluster) {
pw.print("local");
} else {
pw.print("remote");
}
pw.println();
pw.print("Announced by : ");
if (inLocalCluster) {
pw.print("n/a");
} else {
if (parentAnnouncement != null) {
pw.print(parentAnnouncement.getOwnerId());
} else {
pw.print("(changing)");
}
}
pw.println();
pw.println("Properties:");
for(final Map.Entry entry : instanceDescription.getProperties().entrySet()) {
pw.print("- ");
pw.print(entry.getKey());
pw.print(" : ");
pw.print(entry.getValue());
pw.println();
}
pw.println();
pw.println();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy