package org.jboss.narayana.rest.integration;
import org.jboss.jbossts.star.provider.HttpResponseException;
import org.jboss.jbossts.star.util.TxLinkNames;
import org.jboss.jbossts.star.util.TxStatus;
import org.jboss.jbossts.star.util.TxSupport;
import org.jboss.logging.Logger;
import org.jboss.narayana.rest.integration.api.ParticipantDeserializer;
import org.jboss.narayana.rest.integration.api.HeuristicType;
import org.jboss.narayana.rest.integration.api.Participant;
import org.jboss.narayana.rest.integration.api.ParticipantException;
import org.jboss.narayana.rest.integration.api.ParticipantsManager;
import com.arjuna.ats.arjuna.common.Uid;
import org.jboss.narayana.rest.integration.api.VolatileParticipant;
/**
*
* @author <a href="mailto:gytis@redhat.com">Gytis Trikleris</a>
*
*/
public final class ParticipantsManagerImpl implements ParticipantsManager {
private static final Logger LOG = Logger.getLogger(ParticipantsManagerImpl.class);
private String baseUrl;
@Override
public String getBaseUrl() {
return baseUrl;
}
@Override
public void setBaseUrl(final String baseUrl) {
if (LOG.isTraceEnabled()) {
LOG.trace("ParticipantsManagerImpl.setBaseUrl: baseUrl=" + baseUrl);
}
this.baseUrl = baseUrl;
}
@Override
public String enlist(final String applicationId, final String participantEnlistmentURL, final Participant participant) {
if (LOG.isTraceEnabled()) {
LOG.trace("ParticipantsManagerImpl.enlist: applicationId=" + applicationId + ", participantEnlistmentURL="
+ participantEnlistmentURL + ", participant=" + participant);
}
if (baseUrl == null) {
throw new IllegalStateException("Base URL was not defined.");
}
final String participantId = new Uid().toString();
final String participantUrl = getParticipantUrl(participantId, baseUrl);
String participantRecoveryURL = enlistParticipant(participantUrl, participantEnlistmentURL);
ParticipantInformation participantInformation = new ParticipantInformation(participantId, applicationId,
participantRecoveryURL, participant);
participantInformation.setStatus(TxStatus.TransactionActive.name());
ParticipantsContainer.getInstance().addParticipantInformation(participantId, participantInformation);
if (LOG.isTraceEnabled()) {
LOG.trace("ParticipantsManagerImpl.enlist: participant enlisted. participantUrl=" + participantUrl
+ ", participantInformation=" + participantInformation);
}
return participantId;
}
@Override
public void enlistVolatileParticipant(final String volatileParticipantEnlistmentURL,
final VolatileParticipant volatileParticipant) {
if (LOG.isTraceEnabled()) {
LOG.trace("ParticipantsManagerImpl.enlistVolatileParticipant: volatileParticipantEnlistmentURL="
+ volatileParticipantEnlistmentURL + ", volatileParticipant=" + volatileParticipant);
}
if (baseUrl == null) {
throw new IllegalStateException("Base URL was not defined.");
}
final String participantId = new Uid().toString();
final String participantUrl = getVolatileParticipantUrl(participantId, baseUrl);
enlistVolatileParticipant(participantUrl, volatileParticipantEnlistmentURL);
ParticipantsContainer.getInstance().addVolatileParticipant(participantId, volatileParticipant);
if (LOG.isTraceEnabled()) {
LOG.trace("ParticipantsManagerImpl.enlistVolatileParticipant: participant enlisted. participantId="
+ participantId + ", participantUrl=" + participantUrl);
}
}
@Override
public void registerDeserializer(final String applicationId, final ParticipantDeserializer deserializer) {
if (LOG.isTraceEnabled()) {
LOG.trace("ParticipantsManagerImpl.registerDeserializer: applicationId=" + applicationId + ", deserializer="
+ deserializer);
}
RecoveryManager.getInstance().registerDeserializer(applicationId, deserializer);
}
@Override
public void reportHeuristic(String participantId, HeuristicType heuristicType) {
if (LOG.isTraceEnabled()) {
LOG.trace("ParticipantsManagerImpl.reportHeuristic: participantId=" + participantId + ", heuristicType="
+ heuristicType);
}
final ParticipantInformation participantInformation = ParticipantsContainer.getInstance()
.getParticipantInformation(participantId);
switch (heuristicType) {
case HEURISTIC_ROLLBACK:
participantInformation.setStatus(TxStatus.TransactionHeuristicRollback.name());
break;
case HEURISTIC_COMMIT:
participantInformation.setStatus(TxStatus.TransactionHeuristicCommit.name());
break;
case HEURISTIC_HAZARD:
participantInformation.setStatus(TxStatus.TransactionHeuristicHazard.name());
break;
case HEURISTIC_MIXED:
participantInformation.setStatus(TxStatus.TransactionHeuristicMixed.name());
break;
default:
throw new IllegalArgumentException("Unknown heuristic type");
}
RecoveryManager.getInstance().persistParticipantInformation(participantInformation);
}
private String enlistParticipant(final String participantUrl, final String participantEnlistmentURL) {
TxSupport txSupport = new TxSupport();
String participantLinkHeader = txSupport.makeTwoPhaseAwareParticipantLinkHeader(participantUrl, participantUrl);
final String recoveryUrl;
try {
recoveryUrl = txSupport.enlistParticipant(participantEnlistmentURL, participantLinkHeader);
} catch (HttpResponseException e) {
throw new ParticipantException("Failed to enlist participant", e);
}
return recoveryUrl;
}
private void enlistVolatileParticipant(final String participantUrl, final String volatileParticipantEnlistmentURL) {
final StringBuilder linkHeader = new StringBuilder();
linkHeader.append("<").append(participantUrl).append(">; rel=\"")
.append(TxLinkNames.VOLATILE_PARTICIPANT).append("\"");
final String participantLinkHeader = linkHeader.toString();
try {
new TxSupport().enlistVolatileParticipant(volatileParticipantEnlistmentURL, participantLinkHeader);
} catch (HttpResponseException e) {
throw new ParticipantException("Failed to enlist volatile participant", e);
}
}
private String getParticipantUrl(final String participantId, String baseUrl) {
if (!baseUrl.substring(baseUrl.length() - 1).equals("/")) {
baseUrl += "/";
}
return baseUrl + ParticipantResource.BASE_PATH_SEGMENT + "/" + participantId;
}
private String getVolatileParticipantUrl(final String participantId, String baseUrl) {
if (!baseUrl.substring(baseUrl.length() - 1).equals("/")) {
baseUrl += "/";
}
return baseUrl + VolatileParticipantResource.BASE_PATH_SEGMENT + "/" + participantId;
}
}