/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.sa.zookeeper;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.coordinator.client.service.DistributedDataManager;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.log4j.Logger;
import org.apache.zookeeper.KeeperException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* * An Atomic sequence that provides the next unique OrderNumber throughout the ViPR cluster
*
* The number is stored in Zookeeper at the path /config/global/saordernumber
* The lock "saordernumber" is used to gain access
*
* @author dmaddison
*/
@Component
public class OrderNumberSequenceImpl implements OrderNumberSequence {
private static Logger LOG = Logger.getLogger(OrderNumberSequenceImpl.class);
private static final String LOCK_NAME = "saordernumber";
private static final String COUNTER_PATH = "/config/sa/saordernumber";
@Autowired
private CoordinatorClient coordinatorClient;
private InterProcessLock lock;
private DistributedDataManager dataMgr;
@PostConstruct
public void start() {
lock = coordinatorClient.getLock(LOCK_NAME);
dataMgr = coordinatorClient.createDistributedDataManager(COUNTER_PATH);
try {
// Initialize the counter (if we're the first)
lock.acquire();
Object counterPathExists = dataMgr.checkExists(COUNTER_PATH);
if ((counterPathExists == null) || (dataMgr.getData(COUNTER_PATH, false) == null)) {
LOG.info("Initializing Order Number Sequence");
if (counterPathExists == null) {
try {
dataMgr.createNode(COUNTER_PATH, false);
} catch (KeeperException.NodeExistsException e) {
LOG.warn("node already exists: ", e);
}
}
// TODO : Initialize from Database?
dataMgr.putData(COUNTER_PATH, 0L);
}
} catch (Exception e) {
throw new RuntimeException("Starting OrderNumber Sequence", e);
} finally {
try {
lock.release();
} catch (Exception e) {
LOG.error("Error releasing Order Number lock", e);
}
}
}
/** Generates the next order number */
public long nextOrderNumber() {
try {
lock.acquire();
Long currentValue = (Long) dataMgr.getData(COUNTER_PATH, false);
Long newOrderNumber = currentValue + 1;
dataMgr.putData(COUNTER_PATH, newOrderNumber);
return newOrderNumber;
} catch (Exception e) {
throw new RuntimeException("Updating Order Number Lock", e);
} finally {
try {
lock.release();
} catch (Exception e) {
LOG.error("Error releasing Order Number lock", e);
}
}
}
public void setCoordinatorClient(CoordinatorClient coordinatorClient) {
this.coordinatorClient = coordinatorClient;
}
@PreDestroy
public void closeDataManager() {
if (dataMgr != null) {
dataMgr.close();
}
}
}