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

swim.uri.UriPathMapping Maven / Gradle / Ivy

There is a newer version: 3.10.0
Show newest version
// Copyright 2015-2019 SWIM.AI inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package swim.uri;

import java.util.Iterator;
import java.util.Map;
import swim.collections.HashTrieMap;
import swim.util.Murmur3;

final class UriPathMapping extends UriPathMapper {
  final HashTrieMap> table;
  final UriPathMapper wildcard;
  final UriQueryMapper terminal;

  UriPathMapping(HashTrieMap> table, UriPathMapper wildcard, UriQueryMapper terminal) {
    this.table = table;
    this.wildcard = wildcard;
    this.terminal = terminal;
  }

  @Override
  public boolean isEmpty() {
    return this.table.isEmpty() && this.wildcard.isEmpty() && this.terminal.isEmpty();
  }

  @Override
  public int size() {
    int size = 0;
    final Iterator> routes = this.table.valueIterator();
    while (routes.hasNext()) {
      size += routes.next().size();
    }
    size += this.wildcard.size();
    size += this.terminal.size();
    return size;
  }

  @Override
  public boolean containsValue(Object value) {
    final Iterator> routes = this.table.valueIterator();
    while (routes.hasNext()) {
      if (routes.next().containsValue(value)) {
        return true;
      }
    }
    return this.wildcard.containsValue(value) || this.terminal.containsValue(value);
  }

  @Override
  T get(UriPath path, UriQuery query, UriFragment fragment) {
    if (!path.isEmpty()) {
      UriPathMapper mapping = this.table.get(path.head());
      if (mapping == null) {
        mapping = this.wildcard;
      }
      return mapping.get(path.tail(), query, fragment);
    } else {
      return this.terminal.get(query, fragment);
    }
  }

  UriPathMapping merged(UriPathMapping that) {
    HashTrieMap> table = this.table;
    final Iterator>> routes = that.table.iterator();
    while (routes.hasNext()) {
      final Map.Entry> route = routes.next();
      final String segment = route.getKey();
      UriPathMapper mapping = this.table.get(segment);
      if (mapping != null) {
        mapping = mapping.merged(route.getValue());
      } else {
        mapping = route.getValue();
      }
      table = table.updated(segment, mapping);
    }
    final UriPathMapper wildcard = this.wildcard.merged(that.wildcard);
    final UriQueryMapper terminal = this.terminal.merged(that.terminal);
    return new UriPathMapping(table, wildcard, terminal);
  }

  @Override
  UriPathMapper merged(UriPathMapper that) {
    if (that instanceof UriPathMapping) {
      return merged((UriPathMapping) that);
    } else {
      return that;
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  UriPathMapper removed(UriPath path, UriQuery query, UriFragment fragment) {
    if (!path.isEmpty()) {
      final String segment = path.head();
      if (!segment.isEmpty() && segment.charAt(0) == ':') {
        final UriPathMapper oldWildcard = this.wildcard;
        if (oldWildcard != null) {
          final UriPathMapper newWildcard = oldWildcard.removed(path.tail(), query, fragment);
          if (oldWildcard != newWildcard) {
            if (!this.table.isEmpty() || !newWildcard.isEmpty() || !this.terminal.isEmpty()) {
              return new UriPathMapping(this.table, newWildcard, this.terminal);
            } else {
              return (UriPathMapper) empty();
            }
          }
        }
      } else {
        final HashTrieMap> oldTable = this.table;
        final UriPathMapper oldMapping = oldTable.get(segment);
        if (oldMapping != null) {
          final UriPathMapper newMapping = oldMapping.removed(path.tail(), query, fragment);
          if (oldMapping != newMapping) {
            final HashTrieMap> newTable;
            if (!newMapping.isEmpty()) {
              newTable = oldTable.updated(segment, newMapping);
            } else {
              newTable = oldTable.removed(segment);
            }
            if (!newTable.isEmpty() || !this.wildcard.isEmpty() || !this.terminal.isEmpty()) {
              return new UriPathMapping(newTable, this.wildcard, this.terminal);
            } else {
              return (UriPathMapper) empty();
            }
          }
        }
      }
    } else {
      final UriQueryMapper oldTerminal = terminal;
      if (oldTerminal != null) {
        final UriQueryMapper newTerminal = oldTerminal.removed(query, fragment);
        if (oldTerminal != newTerminal) {
          if (!this.table.isEmpty() || !this.wildcard.isEmpty() || !newTerminal.isEmpty()) {
            return new UriPathMapping(this.table, this.wildcard, newTerminal);
          } else {
            return (UriPathMapper) empty();
          }
        }
      }
    }
    return this;
  }

  @SuppressWarnings("unchecked")
  UriPathMapper unmerged(UriPathMapping that) {
    HashTrieMap> table = this.table;
    final Iterator>> routes = that.table.iterator();
    while (routes.hasNext()) {
      final Map.Entry> route = routes.next();
      final String segment = route.getKey();
      UriPathMapper mapping = this.table.get(segment);
      if (mapping != null) {
        mapping = mapping.unmerged(route.getValue());
        if (!mapping.isEmpty()) {
          table = table.updated(segment, mapping);
        } else {
          table = table.removed(segment);
        }
      }
    }
    final UriPathMapper wildcard = this.wildcard.unmerged(that.wildcard);
    final UriQueryMapper terminal = this.terminal.unmerged(that.terminal);
    if (!table.isEmpty() || !wildcard.isEmpty() || !terminal.isEmpty()) {
      return new UriPathMapping(table, wildcard, terminal);
    } else {
      return (UriPathMapper) empty();
    }
  }

  @Override
  UriPathMapper unmerged(UriPathMapper that) {
    if (that instanceof UriPathMapping) {
      return unmerged((UriPathMapping) that);
    } else {
      return this;
    }
  }

  @Override
  public Iterator> iterator() {
    final Iterator> tableIterator = new UriPathMappingEntryIterator(this.table.valueIterator());
    return new UriPathMappingIterator>(tableIterator, this.wildcard.iterator(), this.terminal.iterator());
  }

  @Override
  public Iterator keyIterator() {
    final Iterator tableIterator = new UriPathMappingKeyIterator(this.table.valueIterator());
    return new UriPathMappingIterator(tableIterator, this.wildcard.keyIterator(), this.terminal.keyIterator());
  }

  @Override
  public Iterator valueIterator() {
    final Iterator tableIterator = new UriPathMappingValueIterator(this.table.valueIterator());
    return new UriPathMappingIterator(tableIterator, this.wildcard.valueIterator(), this.terminal.valueIterator());
  }

  @Override
  public boolean equals(Object other) {
    if (this == other) {
      return true;
    } else if (other instanceof UriPathMapping) {
      final UriPathMapping that = (UriPathMapping) other;
      return this.table.equals(that.table) && this.wildcard.equals(that.wildcard)
          && this.terminal.equals(that.terminal);
    }
    return false;
  }

  @Override
  public int hashCode() {
    if (hashSeed == 0) {
      hashSeed = Murmur3.seed(UriPathMapping.class);
    }
    return Murmur3.mash(Murmur3.mix(Murmur3.mix(Murmur3.mix(hashSeed,
        this.table.hashCode()), this.wildcard.hashCode()), terminal.hashCode()));
  }

  private static int hashSeed;
}

final class UriPathMappingIterator implements Iterator {
  final Iterator tableIterator;
  final Iterator wildcardIterator;
  final Iterator terminalIterator;

  UriPathMappingIterator(Iterator tableIterator, Iterator wildcardIterator, Iterator terminalIterator) {
    this.tableIterator = tableIterator;
    this.wildcardIterator = wildcardIterator;
    this.terminalIterator = terminalIterator;
  }

  @Override
  public boolean hasNext() {
    return this.tableIterator.hasNext() || this.wildcardIterator.hasNext() || this.terminalIterator.hasNext();
  }

  @Override
  public T next() {
    if (this.tableIterator.hasNext()) {
      return this.tableIterator.next();
    } else if (this.wildcardIterator.hasNext()) {
      return this.wildcardIterator.next();
    } else {
      return this.terminalIterator.next();
    }
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException();
  }
}

final class UriPathMappingEntryIterator extends FlatteningIterator, Map.Entry> {
  UriPathMappingEntryIterator(Iterator> outer) {
    super(outer);
  }

  @Override
  protected Iterator> childIterator(UriPathMapper parent) {
    return parent.iterator();
  }
}

final class UriPathMappingKeyIterator extends FlatteningIterator, Uri> {
  UriPathMappingKeyIterator(Iterator> outer) {
    super(outer);
  }

  @Override
  protected Iterator childIterator(UriPathMapper parent) {
    return parent.keyIterator();
  }
}

final class UriPathMappingValueIterator extends FlatteningIterator, T> {
  UriPathMappingValueIterator(Iterator> outer) {
    super(outer);
  }

  @Override
  protected Iterator childIterator(UriPathMapper parent) {
    return parent.valueIterator();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy