/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.profileservice.cluster.repository;
import org.jboss.ha.timestamp.TimestampDiscrepancy;
import org.jboss.ha.timestamp.TimestampDiscrepancyService;
import org.jboss.system.server.profileservice.repository.clustered.metadata.RepositoryItemMetadata;
import org.jboss.system.server.profileservice.repository.clustered.sync.AbstractSynchronizationPolicy;
import org.jboss.system.server.profileservice.repository.clustered.sync.SynchronizationPolicy;
/**
* Default implementation of {@link SynchronizationPolicy}.
*
* @author Brian Stansberry
*
* @version $Revision: $
*
*/
public class DefaultSynchronizationPolicy extends AbstractSynchronizationPolicy
{
private TimestampDiscrepancyService timestampService;
public TimestampDiscrepancyService getTimestampService()
{
return timestampService;
}
public void setTimestampService(TimestampDiscrepancyService timestampService)
{
this.timestampService = timestampService;
}
// ---------------------------------------------------- Protected Overrides
/**
* Always accepts merge additions; accepts join additions if the
* time-discrepancy adjusted timestamp of <code>toAdd</code> is later than
* the current time minus {@link #getRemovalTrackingTime() the maximum
* period we track item removals}. The idea of the latter being that if
* a previous version of <code>toAdd</code> was removed more recently than
* that then we should have a record of its removal.
*/
protected boolean acceptAddition(RepositoryItemMetadata toAdd, RepositoryItemMetadata joinersPrevious,
boolean merge)
{
if (merge)
{
return true;
}
else
{
TimestampDiscrepancy addDiscrepancy = getTimestampDiscrepancy(toAdd.getOriginatingNode(), false);
long adjustedTimestamp = addDiscrepancy.getMinLocalTimestamp(toAdd.getTimestamp());
return adjustedTimestamp > System.currentTimeMillis() - getRemovalTrackingTime();
}
}
/**
* Accepts the reincarnation if the time-discrepancy adjusted timestamp of
* <code>reincarnation</code> is at least as recent as the time-discrepancy
* adjusted timestamp of the <code>current</code> item.
*/
protected boolean acceptReincarnation(RepositoryItemMetadata reincarnation, RepositoryItemMetadata current,
boolean merge)
{
TimestampDiscrepancy addDiscrepancy = getTimestampDiscrepancy(reincarnation.getOriginatingNode(), false);
TimestampDiscrepancy deadDiscrepancy = getTimestampDiscrepancy(current.getOriginatingNode(), false);
return isChangeMoreRecent(reincarnation, current, addDiscrepancy, deadDiscrepancy, false);
}
/**
* Rejects removal if <code>sendersView</code> is <code>null</code>, else
* accepts the removal if the time-discrepancy adjusted timestamp of
* <code>sendersView</code> is at least as recent as the time-discrepancy
* adjusted timestamp of the <code>current</code> item.
*/
protected boolean acceptRemoval(RepositoryItemMetadata current, RepositoryItemMetadata sendersView,
boolean merge)
{
if (sendersView == null)
{
return false;
}
TimestampDiscrepancy senderTimestampDiscrepancy = getTimestampDiscrepancy(sendersView.getOriginatingNode(), false);
TimestampDiscrepancy currentTimestampDiscrepancy = getTimestampDiscrepancy(current.getOriginatingNode(), false);
return isChangeMoreRecent(sendersView, current, senderTimestampDiscrepancy, currentTimestampDiscrepancy, true);
}
/**
* Accepts the removal if the time-discrepancy adjusted timestamp of
* <code>update</code> is at least as recent as the time-discrepancy
* adjusted timestamp of the <code>current</code> item.
*/
protected boolean acceptUpdate(RepositoryItemMetadata update, RepositoryItemMetadata current,
boolean merge)
{
TimestampDiscrepancy updateDiscrepancy = getTimestampDiscrepancy(update.getOriginatingNode(), false);
TimestampDiscrepancy currentTimestampDiscrepancy = getTimestampDiscrepancy(current.getOriginatingNode(), false);
return isChangeMoreRecent(update, current, updateDiscrepancy, currentTimestampDiscrepancy, false);
}
// ---------------------------------------------------------------- Private
private static boolean isChangeMoreRecent(RepositoryItemMetadata toChange, RepositoryItemMetadata current,
TimestampDiscrepancy senderTimestampDiscrepancy, TimestampDiscrepancy currentTimestampDiscrepancy, boolean equalAllowed)
{
if (senderTimestampDiscrepancy == null)
{
// Just have to hope for the best
senderTimestampDiscrepancy = TimestampDiscrepancy.NO_DISCREPANCY;
}
if (currentTimestampDiscrepancy == null)
{
// Just have to hope for the best
currentTimestampDiscrepancy = TimestampDiscrepancy.NO_DISCREPANCY;
}
long senderTime, currentTime;
if (toChange.getOriginatingNode().equals(current.getOriginatingNode()))
{
senderTime = toChange.getTimestamp();
currentTime = current.getTimestamp();
}
else
{
senderTime = senderTimestampDiscrepancy.getMinLocalTimestamp(toChange.getTimestamp());
currentTime = currentTimestampDiscrepancy.getMaxLocalTimestamp(current.getTimestamp());
}
return equalAllowed ? senderTime > currentTime :senderTime > currentTime;
}
private TimestampDiscrepancy getTimestampDiscrepancy(String originatingNode, boolean allowStatusCheck)
{
TimestampDiscrepancy td = timestampService.getTimestampDiscrepancy(originatingNode, allowStatusCheck);
// If we don't have a record for the originator, use NO_DISCREPANCY and hope for the best
return td == null ? TimestampDiscrepancy.NO_DISCREPANCY : td;
}
}