boolean handleNewViewNonDelayed()

in src/main/java/org/apache/sling/discovery/commons/providers/base/ViewStateManagerImpl.java [449:596]


    boolean handleNewViewNonDelayed(final BaseTopologyView newView) {
        logger.trace("handleNewViewNonDelayed: start");
        lock.lock();
        try{
            logger.debug("handleNewViewNonDelayed: start, newView={}", newView);
            if (!newView.isCurrent()) {
                logger.error("handleNewViewNonDelayed: newView must be current");
                throw new IllegalArgumentException("newView must be current");
            }
            modCnt++;
            
            if (!isChanging) {
                // verify if there is actually a change between previousView and newView
                // if there isn't, then there is not much point in sending a CHANGING/CHANGED tuple
                // at all
                if (previousView!=null && (previousView.equals(newView) || equalsIgnoreSyncToken(newView))) {
                    // then nothing to send - the view has not changed, and we haven't
                    // sent the CHANGING event - so we should not do anything here
                    logger.debug("handleNewViewNonDelayed: we were not in changing state and new view matches old, so - ignoring");
                    return false;
                }
                if (previousView==null || !onlyDiffersInProperties(newView)) {
                    logger.debug("handleNewViewNonDelayed: implicitly triggering a handleChanging as we were not in changing state");
                    handleChanging();
                    logger.debug("handleNewViewNonDelayed: implicitly triggering of a handleChanging done");
                }
            }
                
            if (!activated) {
                // then all we can do is to pass this on to previoueView
                logger.trace("handleNewViewNonDelayed: setting previousView to {}", newView);
                previousView = newView;
                // plus set the isChanging flag to false
                logger.trace("handleNewViewNonDelayed: setting isChanging to false");
                isChanging = false;
                
                // other than that, we can't currently send any event, before activate
                logger.debug("handleNewViewNonDelayed: not yet activated - ignoring");
                return true;
            }
            
            // now check if the view indeed changed or if it was just the properties
            if (!isChanging && onlyDiffersInProperties(newView)) {
                // well then send a properties changed event only
                // and that one does not go via consistencyservice
                logSilencer.infoOrDebug("handleNewViewNonDelayed-propsChanged", "handleNewViewNonDelayed: properties changed to: "+newView);
                previousView.setNotCurrent();
                enqueueForAll(eventListeners, EventHelper.newPropertiesChangedEvent(previousView, newView));
                logger.trace("handleNewViewNonDelayed: setting previousView to {}", newView);
                previousView = newView;
                return true;
            }
            
            final boolean invokeClusterSyncService;
            if (consistencyService==null) {
                logSilencer.infoOrDebug("handleNewViewNonDelayed-noSyncService", "handleNewViewNonDelayed: no ClusterSyncService set - continuing directly.");
                invokeClusterSyncService = false;
            } else {
                // there used to be a distinction between:
                // * if no previousView is set, then we should invoke the consistencyService
                // * if one was set, then we only invoke it if any instance left the cluster
                // this algorithm would not work though, as the newly joining instance
                // would always have (previousView==null) - thus would always do the syncToken
                // thingy - while the existing instances would think: ah, no instance left,
                // so it is not so urgent to do the syncToken.
                // at which point the joining instance would wait forever for a syncToken 
                // to arrive.
                //
                // which is a long way of saying: if the consistencyService is configured,
                // then we always use it, hence:
                logSilencer.infoOrDebug("handleNewViewNonDelayed-invokeSyncService", "handleNewViewNonDelayed: ClusterSyncService set - invoking...");
                invokeClusterSyncService = true;
            }
                        
            if (invokeClusterSyncService) {
                // if "instances from the local cluster have been removed"
                // then:
                // run the set consistencyService
                final int lastModCnt = modCnt;
                logSilencer.infoOrDebug("handleNewViewNonDelayed-invokeWaitAsync", "handleNewViewNonDelayed: invoking waitForAsyncEvents, then clusterSyncService");
                asyncEventSender.enqueue(new AsyncEvent() {
                    
                    @Override
                    public String toString() {
                        return "the waitForAsyncEvents-flush-token-"+hashCode();
                    }
                    
                    @Override
                    public void trigger() {
                        // when this event is triggered we're guaranteed to have 
                        // no more async events - cos the async events are handled
                        // in a queue and this AsyncEvent was put at the end of the
                        // queue at enqueue time. So now e can go ahead.
                        // the plus using such a token event is that others when
                        // calling waitForAsyncEvent() will get blocked while this
                        // 'token async event' is handled. Which is what we explicitly want.
                        lock.lock();
                        try{
                            if (modCnt!=lastModCnt) {
                                logger.info("handleNewViewNonDelayed/waitForAsyncEvents.run: modCnt changed (from {} to {}) - ignoring",
                                        lastModCnt, modCnt);
                                return;
                            }
                            logSilencer.infoOrDebug("waitForAsyncEvents-asyncRun", "handleNewViewNonDelayed/waitForAsyncEvents.run: done, now invoking consistencyService");
                            consistencyService.sync(newView,
                                    new Runnable() {
                                
                                public void run() {
                                    logger.trace("consistencyService.callback.run: start. acquiring lock...");
                                    lock.lock();
                                    try{
                                        logger.debug("consistencyService.callback.run: lock aquired. (modCnt should be {}, is {})", lastModCnt, modCnt);
                                        if (modCnt!=lastModCnt) {
                                            logger.info("consistencyService.callback.run: modCnt changed (from {} to {}) - ignoring",
                                                    lastModCnt, modCnt);
                                            return;
                                        }
                                        logSilencer.infoOrDebug("consistencyService-callBackRun", "consistencyService.callback.run: invoking doHandleConsistent.");
                                        // else:
                                        doHandleConsistent(newView);
                                    } finally {
                                        lock.unlock();
                                        logger.trace("consistencyService.callback.run: end.");
                                    }
                                }
                                
                            });
                        } finally {
                            lock.unlock();
                        }
                    }
                    
                });
            } else {
                // otherwise we're either told not to use any ClusterSyncService
                // or using it is not applicable at this stage - so continue
                // with sending the TOPOLOGY_CHANGED (or TOPOLOGY_INIT if there
                // are any newly bound topology listeners) directly
                logSilencer.infoOrDebug("handleNewViewNonDelayed-noSyncService-ignore", "handleNewViewNonDelayed: not invoking consistencyService, considering consistent now");
                doHandleConsistent(newView);
            }
            logger.debug("handleNewViewNonDelayed: end");
            return true;
        } finally {
            lock.unlock();
            logger.trace("handleNewViewNonDelayed: finally");
        }
    }