/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.sa.engine;
import javax.annotation.PostConstruct;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.emc.storageos.db.client.model.uimodels.Order;
import com.emc.storageos.db.client.model.uimodels.OrderStatus;
import com.emc.sa.model.dao.ModelClient;
import com.emc.sa.zookeeper.OrderCompletionQueue;
import com.emc.sa.zookeeper.OrderExecutionQueue;
import com.emc.sa.zookeeper.OrderMessage;
import com.emc.storageos.coordinator.client.service.impl.DistributedQueueConsumer;
import com.emc.storageos.coordinator.client.service.DistributedQueueItemProcessedCallback;
/**
* Takes Order Execution Requests off the queue and dispatches them to the Execution Engine
*
* @author dmaddison
*/
@Component
public class ExecutionEngineDispatcher {
private static Logger LOG = Logger.getLogger(ExecutionEngineDispatcher.class);
@Autowired
private OrderExecutionQueue executionQueue;
@Autowired
private OrderCompletionQueue completionQueue;
@Autowired
private ModelClient modelClient;
@Autowired
private ExecutionEngine executionEngine;
@Autowired
private ExecutionEngineMonitor monitor;
@PostConstruct
public void start() throws Exception {
executionQueue.listenForRequests(new Consumer());
}
public void processOrder(Order order) {
try {
monitor.addOrder(order);
executionEngine.executeOrder(order);
monitor.removeOrder(order);
notifyCompletion(order);
} catch (Exception e) {
String message = String.format("Error processing order %s [%s]", order.getOrderNumber(), order.getId());
LOG.error(message, e);
tryMarkOrderAsFailed(order, e);
throw e;
}
}
private void tryMarkOrderAsFailed(Order order, Throwable cause) {
try {
order.setOrderStatus(OrderStatus.ERROR.name());
order.setMessage(ExceptionUtils.getFullStackTrace(cause));
if (modelClient != null) {
modelClient.save(order);
}
} catch (RuntimeException e) {
// Nothing we can do at this point, simply log it
String message = String
.format("Could update state of Order %s [%s]", order.getOrderNumber(), order.getId());
LOG.error(message, e);
}
}
protected void notifyCompletion(Order order) {
String orderId = order.getId().toString();
try {
completionQueue.putItem(new OrderMessage(orderId));
} catch (Exception e) {
LOG.error("Failed to notify of order completion for order: " + orderId, e);
}
}
public class Consumer extends DistributedQueueConsumer<OrderMessage> {
@Override
public void consumeItem(OrderMessage message, DistributedQueueItemProcessedCallback callback) throws Exception {
Order order = getOrder(message);
LOG.info(String.format("Consuming Order %s [%s]", order.getOrderNumber(), order.getId()));
callback.itemProcessed();
processOrder(order);
}
private Order getOrder(OrderMessage message) {
Order order = modelClient.orders().findById(message.getOrderId());
if (order == null) {
throw new IllegalArgumentException("Order not found: " + message.getOrderId());
}
return order;
}
}
public void setModelClient(ModelClient modelClient) {
this.modelClient = modelClient;
}
public void setExecutionQueue(OrderExecutionQueue executionQueue) {
this.executionQueue = executionQueue;
}
public void setCompletionQueue(OrderCompletionQueue completionQueue) {
this.completionQueue = completionQueue;
}
public void setExecutionEngine(ExecutionEngine executionEngine) {
this.executionEngine = executionEngine;
}
}