in src/main/java/org/apache/sling/discovery/impl/cluster/voting/VotingHandler.java [374:520]
private void promote(final ResourceResolver resourceResolver,
final Resource winningVoteResource) throws PersistenceException {
Resource previousViewsResource = ResourceHelper
.getOrCreateResource(
resourceResolver,
config.getPreviousViewPath());
final Resource establishedViewsResource = ResourceHelper
.getOrCreateResource(
resourceResolver,
config.getEstablishedViewPath());
final Resource ongoingVotingsResource = ResourceHelper
.getOrCreateResource(
resourceResolver,
config.getOngoingVotingsPath());
if (logger.isDebugEnabled()) {
logger.debug("promote: previousViewsResource="
+ previousViewsResource.getPath());
logger.debug("promote: establishedViewsResource="
+ establishedViewsResource.getPath());
logger.debug("promote: ongoingVotingsResource="
+ ongoingVotingsResource.getPath());
logger.debug("promote: winningVoteResource="
+ winningVoteResource.getPath());
}
// step 1: remove any nodes under previousViews
final Iterator<Resource> it1 = previousViewsResource.getChildren().iterator();
try{
while (it1.hasNext()) {
Resource previousView = it1.next();
resourceResolver.delete(previousView);
}
} catch(PersistenceException e) {
// if we cannot delete, apply workaround suggested in SLING-3785
logger.error("promote: Could not delete a previous view - trying move next: "+e, e);
ResourceHelper.moveResource(previousViewsResource, config.getPreviousViewPath()+"_trash_"+UUID.randomUUID().toString());
logger.info("promote: recreating the previousviews node");
previousViewsResource = ResourceHelper
.getOrCreateResource(
resourceResolver,
config.getPreviousViewPath());
}
// step 2: retire the existing established view.
// Note that there must always only be one. But if there's more, retire
// them all now.
final Iterator<Resource> it = establishedViewsResource.getChildren()
.iterator();
boolean first = true;
while (it.hasNext()) {
Resource retiredView = it.next();
if (first) {
first = !first;
if (logger.isDebugEnabled()) {
logger.debug("promote: moving the old established view to previous views: "
+ retiredView.getPath());
}
ResourceHelper.moveResource(retiredView,
previousViewsResource.getPath()
+ "/" + retiredView.getName());
} else {
if (logger.isDebugEnabled()) {
logger.debug("promote: retiring an erroneously additionally established node "
+ retiredView.getPath());
}
resourceResolver.delete(retiredView);
}
}
// step 3: move the winning vote resource under the
// establishedViewsResource
// 3a: set the leaderid
final Iterator<Resource> it2 = winningVoteResource.getChild("members")
.getChildren().iterator();
String leaderElectionId = null;
String leaderid = null;
int membersCount = 0;
while (it2.hasNext()) {
Resource aMember = it2.next();
membersCount++;
String leid = aMember.adaptTo(ValueMap.class).get(
"leaderElectionId", String.class);
if (leaderElectionId == null
|| (leid != null && leid.compareTo(leaderElectionId) < 0)) {
leaderElectionId = leid;
leaderid = aMember.getName();
}
}
if (logger.isDebugEnabled()) {
logger.debug("promote: leader is " + leaderid
+ " - with leaderElectionId=" + leaderElectionId);
}
ModifiableValueMap winningVoteMap = winningVoteResource.adaptTo(ModifiableValueMap.class);
winningVoteMap.put("leaderId", leaderid);
winningVoteMap.put("leaderElectionId", leaderElectionId);
winningVoteMap.put("promotedAt", Calendar.getInstance());
winningVoteMap.put("promotedBy", slingId);
// 3b: move the result under /established
final String newEstablishedViewPath = establishedViewsResource.getPath()
+ "/" + winningVoteResource.getName();
logger.info("promote: promoting to new established node (#members: " + membersCount + ", path: "
+ newEstablishedViewPath + ")");
ResourceHelper.moveResource(winningVoteResource, newEstablishedViewPath);
// step 4: delete all ongoing votings...
final Iterable<Resource> ongoingVotingsChildren = ongoingVotingsResource
.getChildren();
if (ongoingVotingsChildren != null) {
Iterator<Resource> it4 = ongoingVotingsChildren.iterator();
while (it4.hasNext()) {
Resource anOngoingVoting = it4.next();
logger.info("promote: deleting ongoing voting: "+anOngoingVoting.getName());
resourceResolver.delete(anOngoingVoting);
}
}
// step 5: make sure there are no duplicate ongoingVotings nodes
// created. if so, cleanup
final Iterator<Resource> it5 = ongoingVotingsResource.getParent()
.getChildren().iterator();
while (it5.hasNext()) {
Resource resource = it5.next();
if (!resource
.getPath()
.startsWith(
config.getOngoingVotingsPath())) {
continue;
}
if (resource
.getPath()
.equals(config.getOngoingVotingsPath())) {
// then it's [0] so to speak .. which we're not cleaning up
continue;
}
logger.warn("promote: cleaning up a duplicate ongoingVotingPath: "
+ resource.getPath());
resourceResolver.delete(resource);
}
logger.debug("promote: done with promotiong. saving.");
resourceResolver.commit();
logger.info("promote: promotion done (#members: " + membersCount + ", path: "
+ newEstablishedViewPath + ")");
}