}
private void handleProcessResponseFromRemote(MessageContext aMessageContext, String aDelegateKey) {
CAS cas = null;
String casReferenceId = null;
Endpoint endpointWithTimer = null;
try {
casReferenceId = aMessageContext.getMessageStringProperty(AsynchAEMessage.CasReference);
endpointWithTimer = lookupEndpoint(aMessageContext.getEndpoint().getEndpoint(),
casReferenceId);
if (endpointWithTimer == null) {
if (UIMAFramework.getLogger(CLASS_NAME).isLoggable(Level.WARNING)) {
UIMAFramework.getLogger(CLASS_NAME).logrb(Level.WARNING, CLASS_NAME.getName(),
"handleProcessResponseFromRemote", UIMAEE_Constants.JMS_LOG_RESOURCE_BUNDLE,
"UIMAEE_invalid_endpoint__WARNING",
new Object[] { aMessageContext.getEndpoint().getEndpoint(), casReferenceId });
}
return;
}
String delegateKey = ((AggregateAnalysisEngineController) getController())
.lookUpDelegateKey(aMessageContext.getEndpoint().getEndpoint());
Delegate delegate = ((AggregateAnalysisEngineController) getController())
.lookupDelegate(delegateKey);
boolean casRemovedFromOutstandingList = delegate.removeCasFromOutstandingList(casReferenceId);
// Check if this process reply message is expected. A message is expected if the Cas Id
// in the message matches an entry in the delegate's outstanding list. This list stores
// ids of CASes sent to the remote delegate pending reply.
if (!casRemovedFromOutstandingList) {
handleUnexpectedMessage(casReferenceId, aMessageContext.getEndpoint());
return;
}
// Increment number of CASes processed by this delegate
if (aDelegateKey != null) {
ServicePerformance delegateServicePerformance = ((AggregateAnalysisEngineController) getController())
.getServicePerformance(aDelegateKey);
if (delegateServicePerformance != null) {
delegateServicePerformance.incrementNumberOfCASesProcessed();
}
}
String xmi = aMessageContext.getStringMessage();
// Fetch entry from the cache for a given Cas Id. The entry contains a CAS that will be used
// during deserialization
CacheEntry cacheEntry = getController().getInProcessCache().getCacheEntryForCAS(
casReferenceId);
CasStateEntry casStateEntry = ((AggregateAnalysisEngineController) getController())
.getLocalCache().lookupEntry(casReferenceId);
if (casStateEntry != null) {
casStateEntry.setReplyReceived();
// Set the key of the delegate that returned the CAS
casStateEntry.setLastDelegate(delegate);
} else {
return; // Cache Entry Not found
}
cas = cacheEntry.getCas();
int totalNumberOfParallelDelegatesProcessingCas = casStateEntry
.getNumberOfParallelDelegates();
if (UIMAFramework.getLogger(CLASS_NAME).isLoggable(Level.FINE)) {
UIMAFramework.getLogger(CLASS_NAME).logrb(Level.FINE, CLASS_NAME.getName(),
"handleProcessResponseFromRemote", UIMAEE_Constants.JMS_LOG_RESOURCE_BUNDLE,
"UIMAEE_number_parallel_delegates_FINE",
new Object[] { totalNumberOfParallelDelegatesProcessingCas });
}
if (cas == null) {
throw new AsynchAEException(Thread.currentThread().getName()
+ "-Cache Does not contain a CAS. Cas Reference Id::" + casReferenceId);
}
if (UIMAFramework.getLogger().isLoggable(Level.FINEST)) {
UIMAFramework.getLogger(CLASS_NAME).logrb(Level.FINEST, CLASS_NAME.getName(),
"handleProcessResponseFromRemote", UIMAEE_Constants.JMS_LOG_RESOURCE_BUNDLE,
"UIMAEE_rcvd_reply_FINEST",
new Object[] { aMessageContext.getEndpoint().getEndpoint(), casReferenceId, xmi });
}
long t1 = getController().getCpuTime();
/* --------------------- */
/** DESERIALIZE THE CAS. */
/* --------------------- */
// check if the CAS is part of the Parallel Step
if (totalNumberOfParallelDelegatesProcessingCas > 1) {
// Synchronized because replies are merged into the same CAS.
synchronized (cas) {
if (UIMAFramework.getLogger(CLASS_NAME).isLoggable(Level.FINEST)) {
UIMAFramework.getLogger(CLASS_NAME).logrb(Level.FINEST, CLASS_NAME.getName(),
"handleProcessResponseFromRemote", UIMAEE_Constants.JMS_LOG_RESOURCE_BUNDLE,
"UIMAEE_delegate_responded_count_FINEST",
new Object[] { casStateEntry.howManyDelegatesResponded(), casReferenceId });
}
// If a delta CAS, merge it while checking that no pre-existing FSs are modified.
if (aMessageContext.getMessageBooleanProperty(AsynchAEMessage.SentDeltaCas)) {
int highWaterMark = cacheEntry.getHighWaterMark();
deserialize(xmi, cas, casReferenceId, highWaterMark, AllowPreexistingFS.disallow);
} else {
// If not a delta CAS (old service), take all of first reply, and merge in the new
// entries in the later replies. Ignoring pre-existing FS for 2.2.2 compatibility
if (casStateEntry.howManyDelegatesResponded() == 0) {
deserialize(xmi, cas, casReferenceId);
} else { // process secondary reply from a parallel step
int highWaterMark = cacheEntry.getHighWaterMark();
deserialize(xmi, cas, casReferenceId, highWaterMark, AllowPreexistingFS.ignore);
}
}
casStateEntry.incrementHowManyDelegatesResponded();
}
} else { // Processing a reply from a non-parallel delegate (binary or delta xmi or xmi)
String serializationStrategy = endpointWithTimer.getSerializer();
if (serializationStrategy.equals("binary")) {
byte[] binaryData = aMessageContext.getByteMessage();
uimaSerializer.deserializeCasFromBinary(binaryData, cas);
} else {
if (aMessageContext.getMessageBooleanProperty(AsynchAEMessage.SentDeltaCas)) {
int highWaterMark = cacheEntry.getHighWaterMark();
deserialize(xmi, cas, casReferenceId, highWaterMark, AllowPreexistingFS.allow);
} else {
deserialize(xmi, cas, casReferenceId);
}
}
}
long timeToDeserializeCAS = getController().getCpuTime() - t1;
getController().getServicePerformance().incrementCasDeserializationTime(timeToDeserializeCAS);
ServicePerformance casStats = getController().getCasStatistics(casReferenceId);
casStats.incrementCasDeserializationTime(timeToDeserializeCAS);
LongNumericStatistic statistic;
if ((statistic = getController().getMonitor().getLongNumericStatistic("",
Monitor.TotalDeserializeTime)) != null) {
statistic.increment(timeToDeserializeCAS);
}
computeStats(aMessageContext, casReferenceId);
// Send CAS for processing when all delegates reply
// totalNumberOfParallelDelegatesProcessingCas indicates how many delegates are processing CAS
// in parallel. Default is 1, meaning only one delegate processes the CAS at the same.
// Otherwise, check if all delegates responded before passing CAS on to the Flow Controller.
// The idea is that all delegates processing one CAS concurrently must respond, before the CAS
// is allowed to move on to the next step.
// HowManyDelegatesResponded is incremented every time a parallel delegate sends response.
if (totalNumberOfParallelDelegatesProcessingCas == 1
|| receivedAllResponsesFromParallelDelegates(casStateEntry,
totalNumberOfParallelDelegatesProcessingCas)) {
super.invokeProcess(cas, casReferenceId, null, aMessageContext, null);
}
} catch (Exception e) {
// Check if the exception was thrown by the Cache while looking up
// the CAS. It may be the case if in the parallel step one thread
// drops the CAS in the Error Handling while another thread processes
// reply from another delegate in the Parallel Step. A race condition
// may occur here. If one thread drops the CAS due to excessive exceptions
// and Flow Controller is configured to drop the CAS, the other thread
// should not be allowed to move the CAS to process()method. The second
// thread will find the CAS missing in the cache and the logic below
// just logs the stale CAS and returns and doesnt attempt to handle
// the missing CAS exception.
if (e instanceof AsynchAEException && e.getMessage() != null
&& e.getMessage().startsWith("Cas Not Found")) {
String key = "N/A";
if (endpointWithTimer != null) {
key = ((AggregateAnalysisEngineController) getController())
.lookUpDelegateKey(endpointWithTimer.getEndpoint());
}
if (UIMAFramework.getLogger(CLASS_NAME).isLoggable(Level.INFO)) {
UIMAFramework.getLogger(CLASS_NAME).logrb(Level.FINEST, CLASS_NAME.getName(),
"handleProcessResponseFromRemote", UIMAEE_Constants.JMS_LOG_RESOURCE_BUNDLE,
"UIMAEE_stale_reply__INFO",