All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openl.util.CategorizedMap Maven / Gradle / Ivy

/*
 * Created on May 29, 2003
 *
 * Developed by Intelligent ChoicePoint Inc. 2003
 */

package org.openl.util;

import java.util.Collection;
import java.util.HashMap;
import java.util.Objects;

/**
 * @author snshor
 */
public class CategorizedMap {

    private static class Category {

        private Category parent;
        private int parentDistance;
        private final String category;

        private Category(String category) {
            this.category = category;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            return Objects.equals(category, ((Category) o).category);
        }

        @Override
        public int hashCode() {
            return Objects.hashCode(category);
        }

        public String getCategory() {
            return category;
        }

        public Category getParent() {
            return parent;
        }

        public int getParentDistance() {
            return parentDistance;
        }

        public void setParent(Category category) {
            parent = category;
        }

        public void setParentDistance(int i) {
            parentDistance = i;
        }

    }

    private final HashMap categories = new HashMap<>();
    protected final HashMap all = new HashMap<>();

    private Object findByCategory(String str) {
        Category c = getCategory(str);
        while ((c = c.parent) != null) {
            Object res = all.get(c.getCategory());
            if (res != null) {
                return res;
            }
        }
        return null;
    }

    /*
     * (non-Javadoc)
     *
     * @see java.util.Map#get(java.lang.Object)
     */
    public Object get(Object key) {
        return getCategorized((String) key);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.openl.env.IResourceProvider#getResource(java.lang.Object)
     */
    private Object getCategorized(String category) {

        Object res = all.get(category);
        return res != null ? res : findByCategory(category);
    }

    public synchronized Category getCategory(String cc) {
        Category c = categories.get(cc);
        if (c == null) {
            c = new Category(cc);
            setParent(c);
            categories.put(cc, c);

            if (c.parent != null) {
                reassignParents(c.getParentDistance(), c.getParent());
            } else {
                reassignParents(-1, null);
            }
        }

        return c;

    }

    public Object put(Object key, Object value) {
        return putCategorized((String) key, value);
    }

    private Object putCategorized(String category, Object value) {
        if (!all.containsKey(category)) {
            getCategory(category);
        }
        return all.put(category, value);
    }

    private synchronized void reassignParents(int parentDistance, Category parent) {
        for (Category c : categories.values()) {
            if (c.getParent() == parent && c.getParentDistance() > parentDistance) {
                setParent(c);
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see java.util.Map#put(java.lang.Object, java.lang.Object)
     */
    protected synchronized void setParent(Category cc) {
        String search = cc.getCategory();

        for (int i = 1; ; ++i) {
            int index = search.lastIndexOf('.');
            if (index < 0) {
                break;
            }
            search = search.substring(0, index);
            Category parent = categories.get(search);
            if (parent != null) {
                cc.setParentDistance(i);
                cc.setParent(parent);
                return;
            }
        }
        cc.setParent(null);
        cc.setParentDistance(0);
    }

    public Collection values() {
        return all.values();
    }

}