Search in sources :

Example 36 with InstanceDescription

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();
}
Also used : ClusterView(org.apache.sling.discovery.ClusterView) Iterator(java.util.Iterator) InstanceDescription(org.apache.sling.discovery.InstanceDescription) InstancesDiff(org.apache.sling.discovery.commons.InstancesDiff)

Example 37 with InstanceDescription

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);
    }
}
Also used : ArrayList(java.util.ArrayList) InstanceDescription(org.apache.sling.discovery.InstanceDescription)

Example 38 with InstanceDescription

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);
        }
    }
}
Also used : ClusterView(org.apache.sling.discovery.ClusterView) JsonException(javax.json.JsonException) Announcement(org.apache.sling.discovery.base.connectors.announcement.Announcement) AnnouncementFilter(org.apache.sling.discovery.base.connectors.announcement.AnnouncementFilter) HttpPut(org.apache.http.client.methods.HttpPut) StringEntity(org.apache.http.entity.StringEntity) ByteArrayEntity(org.apache.http.entity.ByteArrayEntity) GZIPOutputStream(java.util.zip.GZIPOutputStream) Iterator(java.util.Iterator) CloseableHttpResponse(org.apache.http.client.methods.CloseableHttpResponse) CloseableHttpClient(org.apache.http.impl.client.CloseableHttpClient) HttpClientContext(org.apache.http.client.protocol.HttpClientContext) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) Date(java.util.Date) UsernamePasswordCredentials(org.apache.http.auth.UsernamePasswordCredentials) Header(org.apache.http.Header) AuthScope(org.apache.http.auth.AuthScope) UndefinedClusterViewException(org.apache.sling.discovery.base.commons.UndefinedClusterViewException) InstanceDescription(org.apache.sling.discovery.InstanceDescription) Credentials(org.apache.http.auth.Credentials) UsernamePasswordCredentials(org.apache.http.auth.UsernamePasswordCredentials)

Example 39 with InstanceDescription

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;
}
Also used : DefaultInstanceDescription(org.apache.sling.discovery.commons.providers.DefaultInstanceDescription) NonLocalInstanceDescription(org.apache.sling.discovery.commons.providers.NonLocalInstanceDescription) InstanceDescription(org.apache.sling.discovery.InstanceDescription) PersistenceException(org.apache.sling.api.resource.PersistenceException)

Example 40 with InstanceDescription

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;
}
Also used : JsonException(javax.json.JsonException) Resource(org.apache.sling.api.resource.Resource) LinkedList(java.util.LinkedList) ResourceResolver(org.apache.sling.api.resource.ResourceResolver) PersistenceException(org.apache.sling.api.resource.PersistenceException) LoginException(org.apache.sling.api.resource.LoginException) InstanceDescription(org.apache.sling.discovery.InstanceDescription)

Aggregations

InstanceDescription (org.apache.sling.discovery.InstanceDescription)59 ClusterView (org.apache.sling.discovery.ClusterView)16 DefaultInstanceDescription (org.apache.sling.discovery.commons.providers.DefaultInstanceDescription)11 Map (java.util.Map)10 PersistenceException (org.apache.sling.api.resource.PersistenceException)10 TopologyView (org.apache.sling.discovery.TopologyView)9 HashMap (java.util.HashMap)8 LoginException (org.apache.sling.api.resource.LoginException)8 ResourceResolver (org.apache.sling.api.resource.ResourceResolver)8 Test (org.junit.Test)8 Announcement (org.apache.sling.discovery.base.connectors.announcement.Announcement)7 UndefinedClusterViewException (org.apache.sling.discovery.base.commons.UndefinedClusterViewException)6 DefaultClusterView (org.apache.sling.discovery.commons.providers.DefaultClusterView)6 HashSet (java.util.HashSet)5 Resource (org.apache.sling.api.resource.Resource)5 ValueMap (org.apache.sling.api.resource.ValueMap)5 LocalClusterView (org.apache.sling.discovery.commons.providers.spi.LocalClusterView)5 ArrayList (java.util.ArrayList)4 Iterator (java.util.Iterator)4 LinkedList (java.util.LinkedList)4