package de.jpaw.bonaparte.refsp.impl;
import org.joda.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.jpaw.bonaparte.pojos.api.PersistenceProviders;
import de.jpaw.bonaparte.refs.PersistenceProvider;
import de.jpaw.bonaparte.refsp.RequestContext;
/** Base implementation of some request's environment, usually enhanced by specific applications.
*
* For every request, one of these is created.
* Additional ones may be created for the asynchronous log writers (using dummy or null internalHeaderParameters)
*
* Any functionality relating to customization has been moved to a separate class (separation of concerns).
*/
public class AbstractRequestContext implements RequestContext, AutoCloseable {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRequestContext.class);
private static final int MAX_PERSISTENCE_PROVIDERS = PersistenceProviders.values().length; // how many different persistence providers may participate?
public final String userId;
public final String tenantId;
public final long userRef;
public final long tenantRef;
public final long requestRef;
public final Instant executionStart; // to avoid checking the time repeatedly (takes 33 ns every time we do it), a timestamp is taken when the request processing starts
private final PersistenceProvider [] persistenceUnits = new PersistenceProvider[MAX_PERSISTENCE_PROVIDERS];
private int maxPersistenceProvider = -1; // high water mark for the maximum index of a provider
public AbstractRequestContext(Instant executionStart, String userId, String tenantId, long userRef, long tenantRef, long requestRef) {
this.tenantId = tenantId;
this.userId = userId;
this.tenantRef = tenantRef;
this.userRef = userRef;
this.requestRef = requestRef;
this.executionStart = executionStart != null ? executionStart : Instant.now();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Starting RequestContext for user {}, tenant {}, processRef {}", userId, tenantId, Long.valueOf(requestRef));
}
// persistence services
/** Informs the request context that the provider named participates in the transaction. */
@Override
public void addPersistenceContext(PersistenceProvider pprovider) {
int ind = pprovider.getPriority();
if (persistenceUnits[ind] == null) {
persistenceUnits[ind] = pprovider;
if (ind > maxPersistenceProvider)
maxPersistenceProvider = ind;
pprovider.open(); // first time this request has seen it, open it!
}
}
@Override
public PersistenceProvider getPersistenceProvider(int priority) {
return persistenceUnits[priority];
}
@Override
public void commit() throws Exception {
for (int i = 0; i <= maxPersistenceProvider; ++i) {
try {
if (persistenceUnits[i] != null)
persistenceUnits[i].commit();
} catch (Exception e) {
// if the commit fails, we have to roll back the others as well
rollback();
throw e; // throw the original exception here (or convert to return code?)
}
}
for (int i = 0; i <= maxPersistenceProvider; ++i)
if (persistenceUnits[i] != null)
persistenceUnits[i].close();
}
@Override
public void rollback() throws Exception {
for (int i = 0; i <= maxPersistenceProvider; ++i)
if (persistenceUnits[i] != null)
persistenceUnits[i].rollback();
for (int i = 0; i <= maxPersistenceProvider; ++i)
if (persistenceUnits[i] != null)
persistenceUnits[i].close();
}
@Override
public void close() throws Exception {
if (LOGGER.isDebugEnabled())
LOGGER.debug("Closing RequestContext for user {}, tenant {}, processRef {}", userId, tenantId, Long.valueOf(requestRef));
for (int i = 0; i <= maxPersistenceProvider; ++i) {
if (persistenceUnits[i] != null) {
persistenceUnits[i].close();
// clear reference
persistenceUnits[i] = null;
}
}
maxPersistenceProvider = -1;
}
// standard getters as defined in the interface
@Override
public long getTenantRef() {
return tenantRef;
}
@Override
public long getUserRef() {
return userRef;
}
@Override
public long getRequestRef() {
return requestRef;
}
@Override
public Instant getExecutionStart() {
return executionStart;
}
}