public void end()
{
this.owner.checkPermission(name, CoordinationPermission.INITIATE);
if ( !this.isTerminated() && this.associatedThread != null && Thread.currentThread() != this.associatedThread )
{
throw new CoordinationException("Coordination is associated with different thread", this, CoordinationException.WRONG_THREAD);
}
if (startTermination())
{
final CoordinationException nestedFailed = this.owner.endNestedCoordinations(this);
if ( nestedFailed != null )
{
this.failReason = nestedFailed;
}
boolean partialFailure = false;
this.owner.unregister(this, true);
final List<Participant> releaseList = new ArrayList<Participant>();
synchronized ( this.participants )
{
releaseList.addAll(this.participants);
this.participants.clear();
}
// consider failure reason (if not null)
for (int i=releaseList.size()-1;i>=0;i--)
{
final Participant part = releaseList.get(i);
try
{
if ( this.failReason != null )
{
part.failed(this);
}
else
{
part.ended(this);
}
}
catch (final Exception e)
{
LogWrapper.getLogger()
.log(LogWrapper.LOG_ERROR, "Participant threw exception during call to fail()", e);
partialFailure = true;
}
// release the participant for other coordinations
owner.releaseParticipant(part);
}
state = State.TERMINATED;
synchronized (this.waitLock)
{
this.waitLock.notifyAll();
}
this.associatedThread = null;
if ( this.failReason != null )
{
throw new CoordinationException("Nested coordination failed", this,
CoordinationException.FAILED, this.failReason);
}
if (partialFailure)
{
throw new CoordinationException("One or more participants threw while ending the coordination", this,
CoordinationException.PARTIALLY_ENDED);
}
}
else if ( state == State.FAILED )
{
this.owner.unregister(this, true);
state = State.TERMINATED;
throw new CoordinationException("Coordination failed", this, CoordinationException.FAILED, failReason);
}
else
{
// already terminated
throw new CoordinationException("Coordination " + id + "/" + name + " has already terminated", this,
CoordinationException.ALREADY_ENDED);
}
}