001    /*
002    @license.text@
003     */
004    package biz.hammurapi.config;
005    
006    import java.util.ArrayList;
007    import java.util.Collections;
008    import java.util.Comparator;
009    import java.util.HashMap;
010    import java.util.HashSet;
011    import java.util.Iterator;
012    import java.util.List;
013    import java.util.Map;
014    import java.util.Set;
015    
016    import biz.hammurapi.eval.CircularReferenceException;
017    
018    /**
019     * Manages dependencies between objects.
020     * @author Pavel Vlasov
021     * @revision $Revision$
022     */
023    public class DependencyManager {
024            private Map dependencyMap=new HashMap();
025            
026            /**
027             * Adds dependency. Master can be null for independent objects.
028             * @param slave
029             * @param master
030             */
031            public void addDependency(Object slave, Object master) {
032                    Set masters=(Set) dependencyMap.get(slave);
033                    if (masters==null) {
034                            masters=new HashSet();
035                            dependencyMap.put(slave, masters);
036                    }
037                    if (master!=null) {
038                            masters.add(master);
039                    }
040            }
041            
042            /**
043             * Finds out whether slave depends on master directly or indirectly
044             * @param slave
045             * @param master
046             * @return
047             */
048            public boolean isDependent(Object slave, Object master) {
049                    return isDependent(slave, master, slave);
050            }
051    
052            private boolean isDependent(Object slave, Object master, Object originalSlave) {
053                    if (master==originalSlave) {
054                            throw new CircularReferenceException("Circular reference : "+originalSlave);
055                    }
056                    
057                    Set masters=(Set) dependencyMap.get(slave);             
058                    if (masters!=null && masters.contains(master)) {
059                            return true;
060                    }
061                    
062                    Iterator it=masters.iterator();
063                    while (it.hasNext()) {
064                            if (isDependent(it.next(), master, originalSlave)) {
065                                    return true;
066                            }
067                    }
068                    
069                    return false;
070            }
071            
072            /**
073             * @return List of items ordered by dependency - independent items first.
074             */
075            public List getOrdered() {
076                    ArrayList ret=new ArrayList(dependencyMap.keySet());
077                    Collections.sort(
078                                    ret,
079                                    new Comparator() {
080    
081                                            public int compare(Object o1, Object o2) {
082                                                    if (o1==o2) {
083                                                            return 0;                                                       
084                                                    }
085                                                    
086                                                    if (isDependent(o1, o2)) {
087                                                            return 1;
088                                                    }
089                                                    
090                                                    if (isDependent(o2,o1)) {
091                                                            return -1;
092                                                    }
093                                                    
094                                                    return o1.hashCode()-o2.hashCode();
095                                            }
096                                            
097                                    });
098                    return ret;
099            }
100     
101    }