use of org.apache.sling.discovery.base.connectors.announcement.Announcement in project sling by apache.
the class TopologyWebConsolePlugin method printConfiguration.
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<ClusterView> clusters = topology.getClusterViews();
final ClusterView myCluster = topology.getLocalInstance().getClusterView();
printCluster(pw, myCluster, myCluster);
for (Iterator<ClusterView> 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<CachedAnnouncement> 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<TopologyConnectorClientInformation> 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();
}
use of org.apache.sling.discovery.base.connectors.announcement.Announcement in project sling by apache.
the class TopologyWebConsolePlugin method listIncomingTopologyConnectors.
/**
* Render the incoming topology connectors - including the header-div and table
*/
private void listIncomingTopologyConnectors(final PrintWriter pw) {
boolean odd = false;
pw.println("<div class=\"ui-widget-header ui-corner-top buttonGroup\" style=\"height: 15px;\">");
pw.println("<span style=\"float: left; margin-left: 1em;\">Incoming topology connectors</span>");
pw.println("</div>");
pw.println("<table class=\"adapters nicetable ui-widget tablesorter\">");
pw.println("<thead>");
pw.println("<tr>");
pw.println("<th class=\"header ui-widget-header\">Owner slingId</th>");
pw.println("<th class=\"header ui-widget-header\">Server info</th>");
pw.println("<th class=\"header ui-widget-header\">Last heartbeat</th>");
pw.println("<th class=\"header ui-widget-header\">Timeout</th>");
pw.println("</tr>");
pw.println("</thead>");
pw.println("<tbody>");
Collection<CachedAnnouncement> incomingConnections = announcementRegistry.listLocalIncomingAnnouncements();
for (Iterator<CachedAnnouncement> it = incomingConnections.iterator(); it.hasNext(); ) {
CachedAnnouncement incomingCachedAnnouncement = it.next();
Announcement incomingAnnouncement = incomingCachedAnnouncement.getAnnouncement();
String oddEven = odd ? "odd" : "even";
odd = !odd;
pw.println("<tr class=\"" + oddEven + " ui-state-default\">");
pw.println("<td>" + incomingAnnouncement.getOwnerId() + "</td>");
if (incomingAnnouncement.getServerInfo() != null) {
pw.println("<td>" + incomingAnnouncement.getServerInfo() + "</td>");
} else {
pw.println("<td><i>n/a</i></td>");
}
pw.println("<td>" + beautifiedTimeDiff(incomingCachedAnnouncement.getLastPing()) + "</td>");
pw.println("<td>" + beautifiedDueTime(incomingCachedAnnouncement.getSecondsUntilTimeout()) + "</td>");
pw.println("</tr>");
}
pw.println("</tbody>");
pw.println("</table>");
pw.println("<br/>");
pw.println("<br/>");
}
use of org.apache.sling.discovery.base.connectors.announcement.Announcement in project sling by apache.
the class TopologyConnectorClient method ping.
/** ping the server and pass the announcements between the two **/
void ping(final boolean force) {
if (autoStopped) {
// then we suppress any further pings!
logger.debug("ping: autoStopped=true, hence suppressing any further pings.");
return;
}
if (force) {
backoffPeriodEnd = -1;
} else if (backoffPeriodEnd > 0) {
if (System.currentTimeMillis() < backoffPeriodEnd) {
logger.debug("ping: not issueing a heartbeat due to backoff instruction from peer.");
return;
} else {
logger.debug("ping: backoff period ended, issuing another ping now.");
}
}
final String uri = connectorUrl.toString() + "." + clusterViewService.getSlingId() + ".json";
if (logger.isDebugEnabled()) {
logger.debug("ping: connectorUrl=" + connectorUrl + ", complete uri=" + uri);
}
final HttpClientContext clientContext = HttpClientContext.create();
final CloseableHttpClient httpClient = createHttpClient();
final HttpPut putRequest = new HttpPut(uri);
// setting the connection timeout (idle connection, configured in seconds)
putRequest.setConfig(RequestConfig.custom().setConnectTimeout(1000 * config.getSocketConnectTimeout()).build());
Announcement resultingAnnouncement = null;
try {
String userInfo = connectorUrl.getUserInfo();
if (userInfo != null) {
Credentials c = new UsernamePasswordCredentials(userInfo);
clientContext.getCredentialsProvider().setCredentials(new AuthScope(putRequest.getURI().getHost(), putRequest.getURI().getPort()), c);
}
Announcement topologyAnnouncement = new Announcement(clusterViewService.getSlingId());
topologyAnnouncement.setServerInfo(serverInfo);
final ClusterView clusterView;
try {
clusterView = clusterViewService.getLocalClusterView();
} catch (UndefinedClusterViewException e) {
// SLING-5030 : then we cannot ping
logger.warn("ping: no clusterView available at the moment, cannot ping others now: " + e);
return;
}
topologyAnnouncement.setLocalCluster(clusterView);
if (force) {
logger.debug("ping: sending a resetBackoff");
topologyAnnouncement.setResetBackoff(true);
}
announcementRegistry.addAllExcept(topologyAnnouncement, clusterView, new AnnouncementFilter() {
public boolean accept(final String receivingSlingId, final Announcement announcement) {
// filter out announcements that are of old cluster instances
// which I dont really have in my cluster view at the moment
final Iterator<InstanceDescription> it = clusterView.getInstances().iterator();
while (it.hasNext()) {
final InstanceDescription instance = it.next();
if (instance.getSlingId().equals(receivingSlingId)) {
// all fine then
return true;
}
}
// then I should also not propagate that announcement anywhere
return false;
}
});
final String p = requestValidator.encodeMessage(topologyAnnouncement.asJSON());
if (logger.isDebugEnabled()) {
logger.debug("ping: topologyAnnouncement json is: " + p);
}
requestValidator.trustMessage(putRequest, p);
if (config.isGzipConnectorRequestsEnabled()) {
// tell the server that the content is gzipped:
putRequest.addHeader("Content-Encoding", "gzip");
// and gzip the body:
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
gzipOut.write(p.getBytes("UTF-8"));
gzipOut.close();
final byte[] gzippedEncodedJson = baos.toByteArray();
putRequest.setEntity(new ByteArrayEntity(gzippedEncodedJson, ContentType.APPLICATION_JSON));
lastRequestEncoding = "gzip";
} else {
// otherwise plaintext:
final StringEntity plaintext = new StringEntity(p, "UTF-8");
plaintext.setContentType(ContentType.APPLICATION_JSON.getMimeType());
putRequest.setEntity(plaintext);
lastRequestEncoding = "plaintext";
}
// independent of request-gzipping, we do accept the response to be gzipped,
// so indicate this to the server:
putRequest.addHeader("Accept-Encoding", "gzip");
final CloseableHttpResponse response = httpClient.execute(putRequest, clientContext);
if (logger.isDebugEnabled()) {
logger.debug("ping: done. code=" + response.getStatusLine().getStatusCode() + " - " + response.getStatusLine().getReasonPhrase());
}
lastStatusCode = response.getStatusLine().getStatusCode();
lastResponseEncoding = null;
if (response.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK) {
final Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue() != null && contentEncoding.getValue().contains("gzip")) {
lastResponseEncoding = "gzip";
} else {
lastResponseEncoding = "plaintext";
}
// limiting to 16MB, should be way enough
final String responseBody = requestValidator.decodeMessage(putRequest.getURI().getPath(), response);
if (logger.isDebugEnabled()) {
logger.debug("ping: response body=" + responseBody);
}
if (responseBody != null && responseBody.length() > 0) {
Announcement inheritedAnnouncement = Announcement.fromJSON(responseBody);
final long backoffInterval = inheritedAnnouncement.getBackoffInterval();
if (backoffInterval > 0) {
// then reset the backoffPeriodEnd:
/* minus 1 sec to avoid slipping the interval by a few millis */
this.backoffPeriodEnd = System.currentTimeMillis() + (1000 * backoffInterval) - 1000;
logger.debug("ping: servlet instructed to backoff: backoffInterval=" + backoffInterval + ", resulting in period end of " + new Date(backoffPeriodEnd));
} else {
logger.debug("ping: servlet did not instruct any backoff-ing at this stage");
this.backoffPeriodEnd = -1;
}
if (inheritedAnnouncement.isLoop()) {
if (logger.isDebugEnabled()) {
logger.debug("ping: connector response indicated a loop detected. not registering this announcement from " + inheritedAnnouncement.getOwnerId());
}
if (inheritedAnnouncement.getOwnerId().equals(clusterViewService.getSlingId())) {
if (config.isAutoStopLocalLoopEnabled()) {
// results in connected -> false and representsloop -> true
inheritedAnnouncement = null;
// results in isAutoStopped -> true
autoStopped = true;
}
}
} else {
inheritedAnnouncement.setInherited(true);
if (announcementRegistry.registerAnnouncement(inheritedAnnouncement) == -1) {
if (logger.isDebugEnabled()) {
logger.debug("ping: connector response is from an instance which I already see in my topology" + inheritedAnnouncement);
}
statusDetails = "receiving side is seeing me via another path (connector or cluster) already (loop)";
return;
}
}
resultingAnnouncement = inheritedAnnouncement;
statusDetails = null;
} else {
statusDetails = "no response body received";
}
} else {
statusDetails = "got HTTP Status-Code: " + lastStatusCode;
}
// SLING-2882 : reset suppressPingWarnings_ flag in success case
suppressPingWarnings_ = false;
} catch (IOException e) {
// SLING-2882 : set/check the suppressPingWarnings_ flag
if (suppressPingWarnings_) {
if (logger.isDebugEnabled()) {
logger.debug("ping: got IOException: " + e + ", uri=" + uri);
}
} else {
suppressPingWarnings_ = true;
logger.warn("ping: got IOException [suppressing further warns]: " + e + ", uri=" + uri);
}
statusDetails = e.toString();
} catch (JsonException e) {
logger.warn("ping: got JSONException: " + e);
statusDetails = e.toString();
} catch (RuntimeException re) {
logger.warn("ping: got RuntimeException: " + re, re);
statusDetails = re.toString();
} finally {
putRequest.releaseConnection();
lastInheritedAnnouncement = resultingAnnouncement;
lastPingedAt = System.currentTimeMillis();
try {
httpClient.close();
} catch (IOException e) {
logger.error("disconnect: could not close httpClient: " + e, e);
}
}
}
use of org.apache.sling.discovery.base.connectors.announcement.Announcement in project sling by apache.
the class TopologyConnectorServlet method doPut.
@Override
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (!isWhitelisted(request)) {
// in theory it would be 403==forbidden, but that would reveal that
// a resource would exist there in the first place
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
final String[] pathInfo = request.getPathInfo().split("\\.");
final String extension = pathInfo.length == 3 ? pathInfo[2] : "";
if (!"json".equals(extension)) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
final String selector = pathInfo.length == 3 ? pathInfo[1] : "";
String topologyAnnouncementJSON = requestValidator.decodeMessage(request);
if (logger.isDebugEnabled()) {
logger.debug("doPost: incoming topology announcement is: " + topologyAnnouncementJSON);
}
final Announcement incomingTopologyAnnouncement;
try {
incomingTopologyAnnouncement = Announcement.fromJSON(topologyAnnouncementJSON);
if (!incomingTopologyAnnouncement.getOwnerId().equals(selector)) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
String slingId = clusterViewService.getSlingId();
if (slingId == null) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
logger.info("doPut: no slingId available. Service not ready as expected at the moment.");
return;
}
incomingTopologyAnnouncement.removeInherited(slingId);
final Announcement replyAnnouncement = new Announcement(slingId);
long backoffInterval = -1;
ClusterView clusterView = clusterViewService.getLocalClusterView();
if (!incomingTopologyAnnouncement.isCorrectVersion()) {
logger.warn("doPost: rejecting an announcement from an incompatible connector protocol version: " + incomingTopologyAnnouncement);
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
} else if (ClusterViewHelper.contains(clusterView, incomingTopologyAnnouncement.getOwnerId())) {
if (logger.isDebugEnabled()) {
logger.debug("doPost: rejecting an announcement from an instance that is part of my cluster: " + incomingTopologyAnnouncement);
}
// marking as 'loop'
replyAnnouncement.setLoop(true);
backoffInterval = config.getBackoffStandbyInterval();
} else if (ClusterViewHelper.containsAny(clusterView, incomingTopologyAnnouncement.listInstances())) {
if (logger.isDebugEnabled()) {
logger.debug("doPost: rejecting an announcement as it contains instance(s) that is/are part of my cluster: " + incomingTopologyAnnouncement);
}
// marking as 'loop'
replyAnnouncement.setLoop(true);
backoffInterval = config.getBackoffStandbyInterval();
} else {
backoffInterval = announcementRegistry.registerAnnouncement(incomingTopologyAnnouncement);
if (logger.isDebugEnabled()) {
logger.debug("doPost: backoffInterval after registration: " + backoffInterval);
}
if (backoffInterval == -1) {
if (logger.isDebugEnabled()) {
logger.debug("doPost: rejecting an announcement from an instance that I already see in my topology: " + incomingTopologyAnnouncement);
}
// marking as 'loop'
replyAnnouncement.setLoop(true);
backoffInterval = config.getBackoffStandbyInterval();
} else {
// normal, successful case: replying with the part of the topology which this instance sees
replyAnnouncement.setLocalCluster(clusterView);
announcementRegistry.addAllExcept(replyAnnouncement, clusterView, new AnnouncementFilter() {
public boolean accept(final String receivingSlingId, Announcement announcement) {
if (announcement.getPrimaryKey().equals(incomingTopologyAnnouncement.getPrimaryKey())) {
return false;
}
return true;
}
});
}
}
if (backoffInterval > 0) {
replyAnnouncement.setBackoffInterval(backoffInterval);
if (logger.isDebugEnabled()) {
logger.debug("doPost: backoffInterval for client set to " + replyAnnouncement.getBackoffInterval());
}
}
final String p = requestValidator.encodeMessage(replyAnnouncement.asJSON());
requestValidator.trustMessage(response, request, p);
// gzip the response if the client accepts this
final String acceptEncodingHeader = request.getHeader("Accept-Encoding");
if (acceptEncodingHeader != null && acceptEncodingHeader.contains("gzip")) {
// tell the client that the content is gzipped:
response.setHeader("Content-Encoding", "gzip");
// then gzip the body
final GZIPOutputStream gzipOut = new GZIPOutputStream(response.getOutputStream());
gzipOut.write(p.getBytes("UTF-8"));
gzipOut.close();
} else {
// otherwise plaintext
final PrintWriter pw = response.getWriter();
pw.print(p);
pw.flush();
}
} catch (JsonException e) {
logger.error("doPost: Got a JSONException: " + e, e);
response.sendError(500);
} catch (UndefinedClusterViewException e) {
logger.warn("doPost: no clusterView available at the moment - cannot handle connectors now: " + e);
// "please retry, but atm I can't help since I'm isolated"
response.sendError(503);
}
}
use of org.apache.sling.discovery.base.connectors.announcement.Announcement in project sling by apache.
the class AbstractClusterTest method createFromAnnouncement.
private Announcement createFromAnnouncement(final VirtualInstance from) throws UndefinedClusterViewException {
// TODO: refactor TopologyConnectorClient to avoid duplicating code from there (ping())
Announcement topologyAnnouncement = new Announcement(from.slingId);
topologyAnnouncement.setServerInfo(from.slingId);
final ClusterView clusterView = from.getClusterViewService().getLocalClusterView();
topologyAnnouncement.setLocalCluster(clusterView);
from.getAnnouncementRegistry().addAllExcept(topologyAnnouncement, clusterView, new AnnouncementFilter() {
@Override
public boolean accept(final String receivingSlingId, final Announcement announcement) {
// filter out announcements that are of old cluster instances
// which I dont really have in my cluster view at the moment
final Iterator<InstanceDescription> it = clusterView.getInstances().iterator();
while (it.hasNext()) {
final InstanceDescription instance = it.next();
if (instance.getSlingId().equals(receivingSlingId)) {
// all fine then
return true;
}
}
// then I should also not propagate that announcement anywhere
return false;
}
});
return topologyAnnouncement;
}
Aggregations