org.jboss.aerogear.unifiedpush.message.MetricsCollector Maven / Gradle / Ivy
/**
* JBoss, Home of Professional Open Source
* Copyright Red Hat, Inc., and individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.aerogear.unifiedpush.message;
import org.jboss.aerogear.unifiedpush.api.PushMessageInformation;
import org.jboss.aerogear.unifiedpush.api.VariantMetricInformation;
import org.jboss.aerogear.unifiedpush.message.event.PushMessageCompletedEvent;
import org.jboss.aerogear.unifiedpush.message.event.TriggerMetricCollectionEvent;
import org.jboss.aerogear.unifiedpush.message.event.VariantCompletedEvent;
import org.jboss.aerogear.unifiedpush.message.jms.Dequeue;
import org.jboss.aerogear.unifiedpush.message.util.JmsClient;
import org.jboss.aerogear.unifiedpush.service.metrics.PushMessageMetricsService;
import org.jboss.aerogear.unifiedpush.utils.AeroGearLogger;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
/**
* Receives metrics from {@link NotificationDispatcher} and updates the database.
*/
@Stateless
public class MetricsCollector {
private final AeroGearLogger logger = AeroGearLogger.getInstance(MetricsCollector.class);
@Inject
private PushMessageMetricsService metricsService;
@Resource(mappedName = "java:/queue/MetricsQueue")
private Queue metricsQueue;
@Resource(mappedName = "java:/queue/BatchLoadedQueue")
private Queue batchLoadedQueue;
@Resource(mappedName = "java:/queue/AllBatchesLoadedQueue")
private Queue allBatchesLoaded;
@Inject
private Event variantCompleted;
@Inject
private Event pushMessageCompleted;
@Inject
private JmsClient jmsClient;
/**
* Receives variant metrics and update the push message information in a database.
*
* Counts number of loaded device token batches and detects when all batches were loaded and fully served - i.e. the variant was completed.
* When a variant was completed, fires {@link VariantCompletedEvent} CDI event.
*
* Additionally when a variant was completed and there are no more variants to be completed for this variant,
* the {@link PushMessageCompletedEvent} CDI event is fired.
*
* @param event {@link TriggerMetricCollectionEvent} event dequeued from JMS
* @throws JMSException when JMS provider fails to dequeue messages that {@link MetricsCollector} pulls
*/
public void collectMetrics(@Observes @Dequeue TriggerMetricCollectionEvent event) throws JMSException {
final String pushMessageInformationId = event.getPushMessageInformationId();
final PushMessageInformation pushMessageInformation = metricsService.getPushMessageInformation(pushMessageInformationId);
metricsService.lock(pushMessageInformation);
receiveVariantMetricsRemainingInQueues(pushMessageInformation);
for (VariantMetricInformation variantMetricInformation : pushMessageInformation.getVariantInformations()) {
if (areAllBatchesLoaded(variantMetricInformation)) {
pushMessageInformation.setServedVariants(1 + pushMessageInformation.getServedVariants());
logger.fine(String.format("All batches for variant %s were processed", variantMetricInformation.getVariantID()));
variantCompleted.fire(new VariantCompletedEvent(pushMessageInformation.getId(), variantMetricInformation.getVariantID()));
}
}
if (areAllVariantsServed(pushMessageInformation)) {
event.markAllVariantsProcessed();
logger.fine(String.format("All variants for application %s were processed", pushMessageInformation.getId()));
pushMessageCompleted.fire(new PushMessageCompletedEvent(pushMessageInformation.getId()));
}
metricsService.updatePushMessageInformation(pushMessageInformation);
}
private void receiveVariantMetricsRemainingInQueues(PushMessageInformation pushMessageInformation) throws JMSException {
while (true) {
ObjectMessage message = receiveVariantMetricInformation(pushMessageInformation.getId());
if (message == null) {
break;
} else {
updateVariantMetrics(pushMessageInformation, (VariantMetricInformation) message.getObject());
}
}
}
private boolean areAllVariantsServed(PushMessageInformation pushMessageInformation) {
return areIntegersEqual(pushMessageInformation.getServedVariants(), pushMessageInformation.getTotalVariants());
}
private void updateVariantMetrics(PushMessageInformation pushMessageInformation, VariantMetricInformation variantMetricInformation) {
pushMessageInformation.setTotalReceivers(pushMessageInformation.getTotalReceivers() + variantMetricInformation.getReceivers());
int loadedBatches = countLoadedBatches(variantMetricInformation);
variantMetricInformation.setTotalBatches(variantMetricInformation.getTotalBatches() + loadedBatches);
boolean updatedExisting = false;
for (VariantMetricInformation existingMetric : pushMessageInformation.getVariantInformations()) {
if (variantMetricInformation.getVariantID().equals(existingMetric.getVariantID())) {
updatedExisting = true;
updateExistingMetric(existingMetric, variantMetricInformation);
variantMetricInformation = existingMetric;
break;
}
}
if (!updatedExisting) {
pushMessageInformation.addVariantInformations(variantMetricInformation);
}
}
private int countLoadedBatches(VariantMetricInformation variantMetricInformation) {
int loadedBatches = 0;
while (receiveBatchLoadedEvent(variantMetricInformation) != null) {
loadedBatches += 1;
}
return loadedBatches;
}
private boolean areAllBatchesLoaded(VariantMetricInformation variantMetricInformation) {
if (areIntegersEqual(variantMetricInformation.getTotalBatches(), variantMetricInformation.getServedBatches())) {
// if there is no AllBatchesLoaded event in the queue, then all batches weren't loaded yet
return receiveAllBatchedLoadedEvent(variantMetricInformation) != null;
}
return false;
}
private void updateExistingMetric(VariantMetricInformation existing, VariantMetricInformation update) {
existing.setReceivers(existing.getReceivers() + update.getReceivers());
existing.setServedBatches(existing.getServedBatches() + update.getServedBatches());
existing.setTotalBatches(existing.getTotalBatches() + update.getTotalBatches());
if (existing.getDeliveryStatus() == null) {
existing.setDeliveryStatus(update.getDeliveryStatus());
}
if (existing.getDeliveryStatus() == Boolean.TRUE && update.getDeliveryStatus() == Boolean.FALSE) {
existing.setDeliveryStatus(Boolean.FALSE);
}
if (existing.getReason() == null && update.getReason() != null) {
existing.setReason(update.getReason());
}
}
private boolean areIntegersEqual(int i1, int i2) {
return i1 == i2;
}
private ObjectMessage receiveVariantMetricInformation(String pushMessageInformationId) {
return jmsClient.receive().inTransaction().noWait().withSelector("pushMessageInformationId = '%s'", pushMessageInformationId).from(metricsQueue);
}
private ObjectMessage receiveBatchLoadedEvent(VariantMetricInformation variantMetricInformation) {
final String pushMessageInformationId = variantMetricInformation.getPushMessageInformation().getId();
final String variantID = variantMetricInformation.getVariantID();
return jmsClient.receive().inTransaction().noWait().withSelector("variantID = '%s'", variantID + ":" + pushMessageInformationId).from(batchLoadedQueue);
}
private ObjectMessage receiveAllBatchedLoadedEvent(VariantMetricInformation variantMetricInformation) {
final String pushMessageInformationId = variantMetricInformation.getPushMessageInformation().getId();
final String variantID = variantMetricInformation.getVariantID();
return jmsClient.receive().inTransaction().noWait().withSelector("variantID = '%s'", variantID + ":" + pushMessageInformationId).from(allBatchesLoaded);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy