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

io.nextop.Path Maven / Gradle / Ivy

package io.nextop;


import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import rx.functions.Func1;

import javax.annotation.Nullable;
import java.net.URISyntaxException;
import java.util.*;
import java.util.regex.Pattern;

// paths can use "$var" segments
// optionally starts with a '/', see Urls.parseSegments
public class Path {

    public static Path valueOf(String s) {
        final int n = s.length();

        int j;
        if (0 < n && '/' == s.charAt(0)) {
            j = 1;
        } else {
            j = 0;
        }

        LinkedList segments = new LinkedList();
        for (int i = j; i < n; ++i) {
            char c = s.charAt(i);
            if ('?' == c || '#' == c) {
                segments.add(Segment.valueOf(s.substring(j, i)));
                j = n;
                break;
            }
            if ('/' == c) {
                segments.add(Segment.valueOf(s.substring(j, i)));
                j = i + 1;
            }
        }
        if (j < n) {
            segments.add(Segment.valueOf(s.substring(j, n)));
        }

        return new Path(ImmutableList.copyOf(segments));
    }

    public static Path empty() {
        return new Path(Collections.emptyList());
    }


    public final List segments;


    private Path(List segments) {
        this.segments = segments;
    }


    public Path append(String s) {
        return append(valueOf(s));
    }

    public Path append(Path suffix) {
        return new Path(ImmutableList.copyOf(Iterables.concat(segments, suffix.segments)));
    }

    public boolean startsWith(Path prefix) {
        int n = prefix.segments.size();
        int m = segments.size();
        if (m < n) {
            return false;
        }
        for (int i = 0; i < n; ++i) {
            if (!segments.get(i).equals(prefix.segments.get(i))) {
                return false;
            }
        }
        return true;
    }

    public boolean endsWidth(Path suffix) {
        int n = suffix.segments.size();
        int m = segments.size();
        if (m < n) {
            return false;
        }
        for (int i = 0; i < n; ++i) {
            if (!segments.get(m - 1 - i).equals(suffix.segments.get(n - 1 - i))) {
                return false;
            }
        }
        return true;
    }


    ////// FIXED ///////
    /* fixed means all segments are FIXED. To be fixed,
     * VARIABLE need to be replaced with the variable values. */

    public boolean isFixed() {
        for (Segment segment : segments) {
            if (!Segment.Type.FIXED.equals(segment.type)) {
                return false;
            }
        }
        return true;
    }

    public Path fix(Func1 subs) throws URISyntaxException {
        int n = segments.size();
        List fixedSegments = new ArrayList(n);
        for (int i = 0; i < n; ++i) {
            Segment segment = segments.get(i);
            switch (segment.type) {
                case FIXED:
                    fixedSegments.add(segment);
                    break;
                case VARIABLE:
                    Segment subSegment;
                    @Nullable Object subValue = subs.call(segment.value);
                    if (null == subValue) {
                        throw new URISyntaxException(segment.toString(), "No substitution found.", i);
                    }
                    try {
                        subSegment = Segment.valueOf(subValue.toString());
                    } catch (IllegalArgumentException e) {
                        throw new URISyntaxException(segment.toString(), String.format("Substitution not a valid segment: %s", subValue), i);
                    }
                    if (!Segment.Type.FIXED.equals(subSegment.type)) {
                        throw new URISyntaxException(segment.toString(), String.format("Substitution not a fixed segment: %s", subSegment), i);
                    }
                    fixedSegments.add(subSegment);
                    break;
            }
        }
        return new Path(fixedSegments);
    }


    @Override
    public String toString() {
        return "/" + Joiner.on("/").join(segments);
    }

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

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Path)) {
            return false;
        }
        Path b = (Path) obj;
        return segments.equals(b.segments);
    }




    public static final class Segment {
        public static enum Type {
            FIXED,
            VARIABLE
        }


        private static Segment valueOf(String s) {
            int n = s.length();
            if (n <= 0) {
                throw new IllegalArgumentException();
            }
            if ('$' == s.charAt(0)) {
                String value = s.substring(1, n);
                if (!M_VARIABLE.matcher(value).matches()) {
                    throw new IllegalArgumentException();
                }
                return new Segment(Type.VARIABLE, value);
            } else {
                String value = s;
                if (!M_FIXED.matcher(value).matches()) {
                    throw new IllegalArgumentException();
                }
                return new Segment(Type.FIXED, value);
            }
        }


        public final Type type;
        public final String value;

        private Segment(Type type, String value) {
            this.type = type;
            this.value = value;
        }

        @Override
        public String toString() {
            switch (type) {
                case FIXED:
                    return value;
                case VARIABLE:
                    return "$" + value;
                default:
                    throw new IllegalStateException();
            }
        }

        @Override
        public int hashCode() {
            int c = type.hashCode();
            c = 31 * c + value.hashCode();
            return c;
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Segment)) {
                return false;
            }
            Segment b = (Segment) obj;
            return type.equals(b.type) && value.equals(b.value);
        }



        // FIXME ref spec
        private static final Pattern M_FIXED = Pattern.compile("[a-z0-9-_;\\.]+");
        private static final Pattern M_VARIABLE = Pattern.compile("[a-z0-9-\\.]+");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy