use of org.apache.sling.discovery.InstanceDescription in project sling by apache.
the class TopologyWebConsolePlugin method handleTopologyEvent.
/**
* keep a truncated history of the log events for information purpose (to be shown in the webconsole)
*/
@Override
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<InstanceDescription> 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<InstanceDescription> 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<InstanceDescription> newInstances = event.getNewView().getInstances();
for (Iterator<InstanceDescription> 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<String, String> oldProps = oldInstanceDescription.getProperties();
Map<String, String> 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<InstanceDescription> 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<InstanceDescription> 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<InstanceDescription> 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();
}
use of org.apache.sling.discovery.InstanceDescription in project sling by apache.
the class TopologyHandler method handleTopologyEvent.
/**
* @see org.apache.sling.discovery.TopologyEventListener#handleTopologyEvent(org.apache.sling.discovery.TopologyEvent)
*/
@Override
public void handleTopologyEvent(final TopologyEvent event) {
if (event.getType() == Type.TOPOLOGY_INIT || event.getType() == Type.TOPOLOGY_CHANGED) {
final List<String> ids = new ArrayList<>();
for (final InstanceDescription desc : event.getNewView().getInstances()) {
ids.add(desc.getSlingId());
}
Collections.sort(ids);
QuartzJobExecutor.IS_LEADER.set(event.getNewView().getLocalInstance().isLeader());
QuartzJobExecutor.DISCOVERY_INFO_AVAILABLE.set(true);
QuartzJobExecutor.SLING_IDS.set(ids.toArray(new String[ids.size()]));
} else if (event.getType() == Type.TOPOLOGY_CHANGING) {
QuartzJobExecutor.IS_LEADER.set(false);
QuartzJobExecutor.DISCOVERY_INFO_AVAILABLE.set(false);
QuartzJobExecutor.SLING_IDS.set(null);
}
}
use of org.apache.sling.discovery.InstanceDescription 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.InstanceDescription in project sling by apache.
the class Announcement method isValid.
/** check whether this is a valid announcement, containing the minimal information **/
public boolean isValid() {
if (ownerId == null || ownerId.length() == 0) {
return false;
}
if (loop) {
return true;
}
if (!isCorrectVersion()) {
return false;
}
if (localCluster == null) {
return false;
}
try {
List<InstanceDescription> instances = localCluster.getInstances();
if (instances == null || instances.size() == 0) {
return false;
}
boolean isOwnerMemberOfLocalCluster = false;
for (Iterator<InstanceDescription> it = instances.iterator(); it.hasNext(); ) {
InstanceDescription instanceDescription = it.next();
if (instanceDescription.getSlingId().equals(ownerId)) {
isOwnerMemberOfLocalCluster = true;
}
}
if (!isOwnerMemberOfLocalCluster) {
return false;
}
} catch (Exception ise) {
return false;
}
return true;
}
use of org.apache.sling.discovery.InstanceDescription in project sling by apache.
the class AnnouncementRegistryImpl method registerAnnouncement.
@Override
public synchronized long registerAnnouncement(final Announcement topologyAnnouncement) {
if (topologyAnnouncement == null) {
throw new IllegalArgumentException("topologyAnnouncement must not be null");
}
if (!topologyAnnouncement.isValid()) {
logger.warn("topologyAnnouncement is not valid");
return -1;
}
if (resourceResolverFactory == null) {
logger.error("registerAnnouncement: resourceResolverFactory is null");
return -1;
}
final CachedAnnouncement cachedAnnouncement = ownAnnouncementsCache.get(topologyAnnouncement.getOwnerId());
if (cachedAnnouncement != null) {
if (logger.isDebugEnabled()) {
logger.debug("registerAnnouncement: got existing cached announcement for ownerId=" + topologyAnnouncement.getOwnerId());
}
try {
if (topologyAnnouncement.correspondsTo(cachedAnnouncement.getAnnouncement())) {
// then nothing has changed with this announcement, so just update
// the heartbeat and fine is.
// this should actually be the normal case for a stable connector
logger.debug("registerAnnouncement: nothing has changed, only updating heartbeat in-memory.");
return cachedAnnouncement.registerPing(topologyAnnouncement, config);
}
logger.debug("registerAnnouncement: incoming announcement differs from existing one!");
} catch (JsonException e) {
logger.error("registerAnnouncement: got JSONException while converting incoming announcement to JSON: " + e, e);
}
// otherwise the repository and the cache require to be updated
// resetting the cache therefore at this point already
ownAnnouncementsCache.remove(topologyAnnouncement.getOwnerId());
} else {
logger.debug("registerAnnouncement: no cached announcement yet for ownerId=" + topologyAnnouncement.getOwnerId());
}
logger.debug("registerAnnouncement: getting the list of all local announcements");
final Collection<Announcement> announcements = new LinkedList<Announcement>();
fillWithCachedAnnouncements(announcements);
if (logger.isDebugEnabled()) {
logger.debug("registerAnnouncement: list returned: " + (announcements == null ? "null" : announcements.size()));
}
for (Iterator<Announcement> it1 = announcements.iterator(); it1.hasNext(); ) {
Announcement announcement = it1.next();
if (announcement.getOwnerId().equals(topologyAnnouncement.getOwnerId())) {
// then this is from the same owner - skip this
continue;
}
// analyse to see if any of the instances in the announcement
// include the new owner
Collection<InstanceDescription> attachedInstances = announcement.listInstances();
for (Iterator<InstanceDescription> it2 = attachedInstances.iterator(); it2.hasNext(); ) {
InstanceDescription instanceDescription = it2.next();
if (topologyAnnouncement.getOwnerId().equals(instanceDescription.getSlingId())) {
logger.info("registerAnnouncement: already have this instance attached: " + instanceDescription.getSlingId());
return -1;
}
}
}
ResourceResolver resourceResolver = null;
try {
resourceResolver = resourceResolverFactory.getServiceResourceResolver(null);
final Resource announcementsResource = ResourceHelper.getOrCreateResource(resourceResolver, config.getClusterInstancesPath() + "/" + slingId + "/announcements");
topologyAnnouncement.persistTo(announcementsResource);
resourceResolver.commit();
ownAnnouncementsCache.put(topologyAnnouncement.getOwnerId(), new CachedAnnouncement(topologyAnnouncement, config));
} catch (LoginException e) {
logger.error("registerAnnouncement: could not log in administratively: " + e, e);
throw new RuntimeException("Could not log in to repository (" + e + ")", e);
} catch (PersistenceException e) {
logger.error("registerAnnouncement: got a PersistenceException: " + e, e);
throw new RuntimeException("Exception while talking to repository (" + e + ")", e);
} catch (JsonException e) {
logger.error("registerAnnouncement: got a JSONException: " + e, e);
throw new RuntimeException("Exception while converting json (" + e + ")", e);
} finally {
if (resourceResolver != null) {
resourceResolver.close();
}
}
return 0;
}
Aggregations