com.centurylink.mdw.service.data.process.HierarchyCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mdw-services Show documentation
Show all versions of mdw-services Show documentation
MDW is a workflow framework specializing in microservice orchestration
package com.centurylink.mdw.service.data.process;
import com.centurylink.mdw.cache.CacheService;
import com.centurylink.mdw.cache.CachingException;
import com.centurylink.mdw.cache.asset.PackageCache;
import com.centurylink.mdw.common.service.ServiceException;
import com.centurylink.mdw.config.PropertyManager;
import com.centurylink.mdw.constant.PropertyNames;
import com.centurylink.mdw.model.workflow.Process;
import com.centurylink.mdw.model.workflow.*;
import com.centurylink.mdw.services.ServiceLocator;
import com.centurylink.mdw.util.log.LoggerUtil;
import com.centurylink.mdw.util.log.StandardLogger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HierarchyCache implements CacheService {
private static StandardLogger logger = LoggerUtil.getStandardLogger();
private static final String MILESTONES_PACKAGE = "com.centurylink.mdw.milestones";
private static volatile Map>> hierarchies = new HashMap<>();
// latest processIds to milestone hierarchies (TODO: map by assetPath for clarity)
private static volatile Map> milestones = new HashMap<>();
private static volatile Map> activityHierarchies = new HashMap<>();
private static volatile List milestoned = null;
public static List> getHierarchy(Long processId) {
List> hierarchy;
Map>> hierarchyMap = hierarchies;
if (hierarchyMap.containsKey(processId)){
hierarchy = hierarchyMap.get(processId);
} else {
synchronized(HierarchyCache.class) {
hierarchyMap = hierarchies;
if (hierarchyMap.containsKey(processId)) {
hierarchy = hierarchyMap.get(processId);
} else {
hierarchy = loadHierarchy(processId, true);
// null values are stored to avoid repeated processing
hierarchies.put(processId, hierarchy);
}
}
}
return hierarchy;
}
private static List> loadHierarchy(Long processId, boolean downward) {
try {
return ServiceLocator.getDesignServices().getProcessHierarchy(processId, downward);
} catch (ServiceException ex) {
throw new CachingException("Failed to load hierarchy for: " + processId, ex);
}
}
/**
* Descending milestones starting with the specified process.
*/
public static Linked getMilestones(Long processId) throws IOException {
Linked processMilestones;
Map> milestoneMap = milestones;
if (milestoneMap.containsKey(processId)) {
processMilestones = milestoneMap.get(processId);
} else {
synchronized (HierarchyCache.class) {
milestoneMap = milestones;
if (milestoneMap.containsKey(processId)) {
processMilestones = milestoneMap.get(processId);
} else {
processMilestones = loadMilestones(processId);
// null values are stored to avoid repeated processing
milestones.put(processId, processMilestones);
}
}
}
return processMilestones;
}
private static Linked loadMilestones(Long processId) throws IOException {
if (PackageCache.getPackage(MILESTONES_PACKAGE) == null)
return null; // don't bother and save some time
Process process = ProcessCache.getProcess(processId);
if (process != null) {
MilestoneFactory milestoneFactory = new MilestoneFactory(process);
Linked start = milestoneFactory.start();
Linked activityHierarchy = getActivityHierarchy(processId);
if (activityHierarchy != null)
addMilestones(start, activityHierarchy);
if (!start.getChildren().isEmpty())
return start;
}
return null;
}
private static void addMilestones(Linked head, Linked start) throws IOException {
Activity activity = start.get();
Process process = ProcessCache.getProcess(activity.getProcessId());
Milestone milestone = new MilestoneFactory(process).getMilestone(activity);
if (milestone != null) {
Linked linkedMilestone = new Linked<>(milestone);
if (!head.getChildren().contains(linkedMilestone)) {
// otherwise already reached here from another path
linkedMilestone.setParent(head);
head.getChildren().add(linkedMilestone);
for (Linked child : start.getChildren()) {
addMilestones(linkedMilestone, child);
}
}
}
else {
for (Linked child : start.getChildren()) {
addMilestones(head, child);
}
}
}
public static Linked getActivityHierarchy(Long processId) throws IOException {
Linked hierarchy;
Map> endToEndMap = activityHierarchies;
if (endToEndMap.containsKey(processId)) {
hierarchy = endToEndMap.get(processId);
}
else {
synchronized (HierarchyCache.class) {
endToEndMap = activityHierarchies;
if (endToEndMap.containsKey(processId)) {
hierarchy = endToEndMap.get(processId);
} else {
hierarchy = loadActivityHierarchy(processId);
activityHierarchies.put(processId, hierarchy);
}
}
}
return hierarchy;
}
private static int MAX_DEPTH;
private static Linked loadActivityHierarchy(Long processId) throws IOException {
if (PackageCache.getPackage(MILESTONES_PACKAGE) == null)
return null; // don't bother and save some time
MAX_DEPTH = PropertyManager.getIntegerProperty(PropertyNames.MDW_MILESTONE_MAX_DEPTH, 7500);
Process process = ProcessCache.getProcess(processId);
if (process != null) {
Linked hierarchy = getHierarchy(processId).get(0);
Linked endToEndActivities = process.getLinkedActivities();
ScopedActivity scoped = new ScopedActivity(hierarchy, endToEndActivities);
addSubprocessActivities(scoped, null);
return endToEndActivities;
}
return null;
}
/**
* Activities are scoped to avoid process invocation circularity.
*/
private static void addSubprocessActivities(ScopedActivity start, List downstreams)
throws IOException {
if (start.depth() > MAX_DEPTH)
return;
List furtherDowns = downstreams;
for (ScopedActivity scopedChild : start.getScopedChildren()) {
Activity activity = scopedChild.get();
List> subhierarchies = getInvoked(scopedChild);
if (!subhierarchies.isEmpty()) {
// link downstream children
if (furtherDowns != null) {
for (Linked downstreamChild : scopedChild.getChildren()) {
for (Linked end : downstreamChild.getEnds()) {
if (end.get().isStop()) {
end.setChildren(new ArrayList<>(furtherDowns));
}
}
}
}
if (activity.isSynchronous()) {
furtherDowns = scopedChild.getScopedChildren();
scopedChild.setChildren(new ArrayList<>());
}
for (Linked subhierarchy : subhierarchies) {
Process loadedSub = ProcessCache.getProcess(subhierarchy.get().getId());
Linked subprocActivities = loadedSub.getLinkedActivities();
scopedChild.getChildren().add(subprocActivities);
subprocActivities.setParent(scopedChild);
ScopedActivity subprocScoped = new ScopedActivity(subhierarchy, subprocActivities);
addSubprocessActivities(subprocScoped, furtherDowns);
}
furtherDowns = downstreams;
}
else {
// non-invoker
if (scopedChild.get().isStop() && scopedChild.getChildren().isEmpty() ) {
if (furtherDowns != null) {
scopedChild.setChildren(new ArrayList<>(furtherDowns));
furtherDowns = null;
}
}
addSubprocessActivities(scopedChild, furtherDowns);
}
}
}
/**
* Omits invoked subflows that would cause circularity by consulting relevant process hierarchy.
*/
private static List> getInvoked(ScopedActivity scopedActivity) {
List> invoked = new ArrayList<>();
for (Linked subprocess : scopedActivity.findInvoked(ProcessCache.getProcesses(false))) {
if (!isIgnored(subprocess.get()))
invoked.add(subprocess);
}
return invoked;
}
/**
* Processes with milestones in their hierarchies.
*/
public static List getMilestoned() {
List milestonedTemp = milestoned;
if (milestonedTemp == null)
synchronized(HierarchyCache.class) {
milestonedTemp = milestoned;
if (milestonedTemp == null)
milestoned = milestonedTemp = loadMilestoned();
}
return milestonedTemp;
}
private static List loadMilestoned() {
List milestoned = new ArrayList<>();
if (PackageCache.getPackage(MILESTONES_PACKAGE) != null) {
for (Process process : ProcessCache.getProcesses(false)) {
try {
List> hierarchyList = getHierarchy(process.getId());
if (!hierarchyList.isEmpty()) {
if (hasMilestones(hierarchyList.get(0))) {
milestoned.add(process.getId());
}
}
}
catch (CachingException ex) {
logger.error("Cannot check milestones for process " + process.getLabel(), ex);
}
}
}
return milestoned;
}
public static boolean hasMilestones(Long processId) {
return getMilestoned().contains(processId);
}
private static boolean hasMilestones(Linked hierarchy) {
Process process = hierarchy.get();
Linked start = process.getLinkedActivities();
if (hasMilestones(new MilestoneFactory(process), start))
return true;
for (Linked child : hierarchy.getChildren()) {
if (hasMilestones(child))
return true;
}
return false;
}
private static boolean hasMilestones(MilestoneFactory factory, Linked start) {
if (factory.getMilestone(start.get()) != null)
return true;
for (Linked child : start.getChildren()) {
if (hasMilestones(factory, child))
return true;
}
return false;
}
@Override
public void clearCache() {
synchronized(HierarchyCache.class) {
hierarchies = new HashMap<>();
milestones = new HashMap<>();
activityHierarchies = new HashMap<>();
milestoned = null;
}
}
@Override
public void refreshCache() {
// hierarchies are lazily loaded
clearCache();
}
private static List IGNORES;
private static boolean isIgnored(Process process) {
if (IGNORES == null) {
List ignores = PropertyManager.getListProperty(PropertyNames.MDW_MILESTONE_IGNORES);
IGNORES = ignores == null ? new ArrayList<>() : ignores;
}
return IGNORES.contains(process.getPackageName() + "/" + process.getName() + ".proc");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy