001    /*
002    @license.text@
003     */
004    package biz.hammurapi.config;
005    
006    import biz.hammurapi.util.Attributable;
007    
008    /**
009     * Helper class to navigate context trees. Follows unix filesystem naming convention: / is a path separator,
010     * . is current element, .. is parent element, absolute path starts with /
011     * @author Pavel Vlasov
012     * @revision $Revision$
013     */
014    public abstract class PathNavigator implements Context {
015            
016            protected Object master;
017    
018            public PathNavigator(Object master) {
019                    this.master=master;
020            }
021    
022            protected abstract Object getParent();
023            protected abstract Object getChild(String name);
024            
025            public Object get(String name) {
026                    try {
027                            Object ret=lookup(name);
028                            if (ret instanceof Service) {
029                                    ((Service) ret).start();
030                            }
031                            
032                            if (ret instanceof Wrapper) {
033                                    ret = ((Wrapper) ret).getMaster();
034                            }
035                            
036                            if (ret instanceof Service) {
037                                    ((Service) ret).start();
038                            }
039                            
040                            return ret;
041                    } catch (ConfigurationException e) {
042                            throw new RuntimeConfigurationException(e);
043                    }
044            }
045            
046            private Object lookup(String name) {
047                    if (name.startsWith("/")) {
048                            if (getParent() instanceof Context) {
049                                    return ((Context) getParent()).get(name);
050                            } 
051                            return name.equals("/") ? master : get(name.substring(1));
052                    } else if ("..".equals(name)) {
053                            return getParent();                     
054                    } else if (name.startsWith("../")) {
055                            return (getParent() instanceof Context) ? ((Context) getParent()).get(name.substring(3)) : null;
056                    } 
057                    
058                    int idx=name.indexOf('/');
059                    if (idx==-1) {
060                            if (name.startsWith("@") && master instanceof Attributable) {
061                                    return ((Attributable) master).getAttribute(name.substring(1));
062                            } 
063                            
064                            return ".".equals(name) ? master : getChild(name);
065                    }
066                    
067                    String nameElement = name.substring(0, idx);
068                    Object child = ".".equals(nameElement) ? master : getChild(nameElement);
069                    if (child instanceof Context) {
070                            return ((Context) child).get(name.substring(idx+1));
071                    }
072                    
073                    return null;            
074            }
075            
076            /**
077             * @param master Master context.
078             * @param parent Parent object.
079             * @return Instance of PathNavigator.
080             */
081            public static Context newInstance(Context master, final Object parent) {
082                    return new PathNavigator(master) {
083    
084                            protected Object getParent() {
085                                    return parent;
086                            }
087    
088                            protected Object getChild(String name) {
089                                    return ((Context) master).get(name);
090                            }
091                            
092                    };
093            }
094    
095    }