package org.cad.interruptus.service; import com.google.common.base.Strings; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.curator.framework.CuratorFramework; import org.apache.zookeeper.data.Stat; import org.cad.interruptus.Message; import org.cad.interruptus.entity.Type; import org.cad.interruptus.repository.TypeRepository; public class InventoryService { final Map<String, Set<String>> typeInventory = new HashMap<>(); final ScheduledExecutorService scheduler; final CuratorFramework curator; final AtomicBoolean isLeader; final String rootPath; final Log logger = LogFactory.getLog(getClass()); final TypeRepository repository; ScheduledFuture scheduledFuture; Integer interval = 5; public InventoryService(final TypeRepository repository, final CuratorFramework curator, final ScheduledExecutorService scheduler, final AtomicBoolean isLeader, final String rootPath) { this.repository = repository; this.scheduler = scheduler; this.curator = curator; this.isLeader = isLeader; this.rootPath = rootPath; } public void setInterval(final Integer interval) { this.interval = interval; } public void start() { scheduledFuture = scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { saveInventoryData(); } catch (Exception ex) { logger.error(this, ex); } } }, interval, interval, TimeUnit.SECONDS); } public void stop() throws Exception { saveInventoryData(); if (scheduledFuture == null) { return; } scheduledFuture.cancel(false); } public void collect(final Message message) { if ( ! isLeader.get()) { return; } final String typeName = message.getType(); final Map<String, Object> body = message.getBody(); try { collectData(typeName, body); } catch (Exception ex) { logger.error(this, ex); } } protected void saveInventoryData() throws Exception { if (typeInventory.isEmpty()) { return; } for (Map.Entry<String, Set<String>> entry : typeInventory.entrySet()) { final String type = entry.getKey(); final Set<String> data = entry.getValue(); saveTypeData(type, data); } typeInventory.clear(); } protected void saveTypeData(final String typeName, final Set<String> data) throws Exception { if (data.isEmpty()) { return; } for (final String hierarchy : data) { final String path = getInventoryPath(typeName, hierarchy); final Stat status = curator.checkExists().forPath(path); if (status != null) { continue; } logger.debug("Create inventory : " + path); curator.create() .creatingParentsIfNeeded() .forPath(path); } } protected void collectData(final String typeName, final Map<String, Object> body) throws Exception { final Type type = repository.findById(typeName); final String hierarchy = type.getHierarchy(); if (hierarchy == null) { return; } final Set<String> inventory = getInventory(typeName); final String[] treeSet = hierarchy.split("\\."); final StringBuffer pathBuffer = new StringBuffer(); for (final String property : treeSet) { final Object value = body.get(property); final String path = "/" + value; pathBuffer.append(path); inventory.add(pathBuffer.toString()); } } protected Set<String> getInventory(final String typeName) throws Exception { if ( ! typeInventory.containsKey(typeName)) { typeInventory.put(typeName, new TreeSet<String>()); } return typeInventory.get(typeName); } protected String getInventoryPath(final String typeName, final String path) { if (Strings.isNullOrEmpty(path)) { return rootPath + "/" + typeName; } if (path.startsWith("/")) { return rootPath + "/" + typeName + path; } return rootPath + "/" + typeName + "/" + path; } public Set<String> getTypeHierarchyInventory(final String typeName, final String hierarchy) throws Exception { final String path = getInventoryPath(typeName, hierarchy); final Stat status = curator.checkExists().forPath(path); if (status == null) { return Collections.EMPTY_SET; } return new TreeSet<>(curator.getChildren().forPath(path)); } }