final String uri = connectorUrl.toString()+"."+clusterViewService.getSlingId()+".json";
if (logger.isDebugEnabled()) {
logger.debug("ping: connectorUrl=" + connectorUrl + ", complete uri=" + uri);
}
HttpClient httpClient = new HttpClient();
final PutMethod method = new PutMethod(uri);
Announcement resultingAnnouncement = null;
try {
String userInfo = connectorUrl.getUserInfo();
if (userInfo != null) {
Credentials c = new UsernamePasswordCredentials(userInfo);
httpClient.getState().setCredentials(
new AuthScope(method.getURI().getHost(), method
.getURI().getPort()), c);
}
Announcement topologyAnnouncement = new Announcement(
clusterViewService.getSlingId());
topologyAnnouncement.setServerInfo(serverInfo);
final ClusterView clusterView = clusterViewService
.getClusterView();
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 =
clusterViewService.getClusterView().getInstances().iterator();
while(it.hasNext()) {
final InstanceDescription instance = it.next();
if (instance.getSlingId().equals(receivingSlingId)) {
// then I have the receiving instance in my cluster view
// all fine then
return true;
}
}
// looks like I dont have the receiving instance in my cluster view
// 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(method, p);
if (config.isGzipConnectorRequestsEnabled()) {
// tell the server that the content is gzipped:
method.addRequestHeader("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();
method.setRequestEntity(new ByteArrayRequestEntity(gzippedEncodedJson, "application/json"));
lastRequestEncoding = "gzip";
} else {
// otherwise plaintext:
method.setRequestEntity(new StringRequestEntity(p, "application/json", "UTF-8"));
lastRequestEncoding = "plaintext";
}
// independent of request-gzipping, we do accept the response to be gzipped,
// so indicate this to the server:
method.addRequestHeader("Accept-Encoding", "gzip");
DefaultHttpMethodRetryHandler retryhandler = new DefaultHttpMethodRetryHandler(0, false);
httpClient.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryhandler);
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(1000*config.getConnectionTimeout());
httpClient.getHttpConnectionManager().getParams().setSoTimeout(1000*config.getSoTimeout());
method.getParams().setSoTimeout(1000*config.getSoTimeout());
httpClient.executeMethod(method);
if (logger.isDebugEnabled()) {
logger.debug("ping: done. code=" + method.getStatusCode() + " - "
+ method.getStatusText());
}
lastStatusCode = method.getStatusCode();
lastResponseEncoding = null;
if (method.getStatusCode()==HttpServletResponse.SC_OK) {
final Header contentEncoding = method.getResponseHeader("Content-Encoding");
if (contentEncoding!=null && contentEncoding.getValue()!=null &&
contentEncoding.getValue().contains("gzip")) {
lastResponseEncoding = "gzip";
} else {
lastResponseEncoding = "plaintext";
}
String responseBody = requestValidator.decodeMessage(method); // limiting to 16MB, should be way enough
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())) {
// SLING-3316 : local-loop detected. Check config to see if we should stop this connector
if (config.isAutoStopLocalLoopEnabled()) {
inheritedAnnouncement = null; // results in connected -> false and representsloop -> true
autoStopped = true; // results in isAutoStopped -> 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 (URIException e) {
logger.warn("ping: Got URIException: " + e + ", uri=" + uri);
statusDetails = e.toString();
} 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 {
method.releaseConnection();
lastInheritedAnnouncement = resultingAnnouncement;
lastPingedAt = System.currentTimeMillis();
}
}