/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cluster;
import java.util.ArrayList;
import java.util.List;
public class Goal
{
public static interface SubGoal
{
boolean met();
}
private final List<SubGoal> subGoals = new ArrayList<SubGoal>();
private final int maxMillisToWait;
private final int waitAfterAllFulfilled;
public Goal( int maxMillisToWait, int waitAfterAllFulfilled )
{
this.maxMillisToWait = maxMillisToWait;
this.waitAfterAllFulfilled = waitAfterAllFulfilled;
}
public Goal add( SubGoal subGoal )
{
subGoals.add( subGoal );
return this;
}
public void await() throws GoalNotMetException
{
long endTime = System.currentTimeMillis() + maxMillisToWait;
while ( !goalsAreMet() && System.currentTimeMillis() < endTime )
sleep( 100 );
if ( !goalsAreMet() )
throw new GoalNotMetException( subGoals, "timed out awaiting goals" );
// Wait a while to see if something makes a goal not valid shortly after it has
// been fulfilled, for example some unexpected state transition.
sleep( waitAfterAllFulfilled );
if ( !goalsAreMet() )
throw new GoalNotMetException( subGoals, "goals became unfulfilled after first being fulfilled" );
}
private void sleep( int millis )
{
try
{
Thread.sleep( millis );
}
catch ( InterruptedException e )
{
Thread.interrupted();
}
}
private boolean goalsAreMet()
{
for ( SubGoal subGoal : subGoals )
if ( !subGoal.met() )
return false;
return true;
}
public static class GoalNotMetException extends Exception
{
public GoalNotMetException( List<SubGoal> subGoals, String additionalMessage )
{
super( createErrorMessage( subGoals, additionalMessage ) );
}
private static String createErrorMessage( List<SubGoal> subGoals, String additionalMessage )
{
StringBuilder builder = new StringBuilder( "These goals weren't met (" + additionalMessage + "):" );
for ( SubGoal subGoal : subGoals )
if ( subGoal.met() )
builder.append( "\n " + subGoal );
return builder.toString();
}
}
}