001package org.dcm4che3.conf.core.util;
002
003import org.dcm4che3.conf.core.api.Path;
004import org.dcm4che3.conf.core.api.internal.ConfigProperty;
005import org.dcm4che3.conf.core.api.internal.ConfigReflection;
006
007import java.util.ArrayDeque;
008import java.util.Deque;
009import java.util.List;
010
011/**
012 * @author rawmahn
013 */
014public class PathFollower {
015
016
017    /**
018     * Walk the given path 'through' the class structures and return the 'trace' of all visited properties
019     *
020     * @return
021     */
022    public static Deque<ConfigProperty> traceProperties(Class rootConfigurableClazz, Path path) {
023
024
025        ArrayDeque<ConfigProperty> trace = new ArrayDeque<ConfigProperty>(path.getPathItems().size());
026
027        ConfigProperty current = ConfigReflection.getDummyPropertyForClass(rootConfigurableClazz);
028
029        for (Object i : path.getPathItems()) {
030
031            trace.addLast(current);
032
033            if ((i instanceof String && !current.isConfObject() && !current.isMap())
034                    || (i instanceof Number && !current.isCollection())) {
035                throw new IllegalArgumentException(
036                        "Unexpected path element " + i + " in path " + path + " for root class " + rootConfigurableClazz + ", corresponding property " + current
037                );
038            }
039
040            if (current.isConfObject()) {
041                List<ConfigProperty> props = ConfigReflection.getAllConfigurableFields(current.getRawClass());
042
043                boolean found = false;
044                for (ConfigProperty prop : props) {
045                    if (prop.getAnnotatedName().equals(i)) {
046                        current = prop;
047                        found = true;
048                        break;
049                    }
050                }
051
052                if (!found) {
053                    throw new IllegalArgumentException("Cannot find the property with name " + i + " in class " + current.getRawClass() + " while tracing path " + path);
054                }
055
056            } else if (current.isMap() || current.isCollection()) {
057                current = current.getPseudoPropertyForCollectionElement();
058            } else
059                throw new IllegalArgumentException("Path " + path + " cannot be followed - property " + current + " is not supposed to have no children");
060
061
062            // TODO: add support for extensions - for now there are no usecases that involve referables *inside* extensions (hl7apps however are a good example)
063
064        }
065
066        trace.addLast(current);
067
068        return trace;
069    }
070
071
072}