001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl.filter.ruletree; 020 021import java.util.Arrays; 022import java.util.List; 023import java.util.concurrent.atomic.AtomicInteger; 024import java.util.stream.Stream; 025 026import static java.util.stream.Collectors.toList; 027 028/** 029 * Prefix tree for paths: if you step on a path prefix that exists, you are good to go. 030 * This class parses a text file that has a prefix on each line: 031 * <ul> 032 * <li>ignored/formatting - each line starting with {@code '#'} (hash) or being empty/blank is ignored.</li> 033 * <li>a path prefix ie "/org/apache/maven".</li> 034 * </ul> 035 * By default, artifact is allowed if layout converted path of it has a matching prefix in this file. 036 * 037 * Example prefix files: 038 * <ul> 039 * <li><a href="https://repo.maven.apache.org/maven2/.meta/prefixes.txt">Maven Central</a></li> 040 * <li><a href="https://repository.apache.org/content/repositories/releases/.meta/prefixes.txt">ASF Releases</a></li> 041 * <li><a href="https://repo.eclipse.org/content/repositories/tycho/.meta/prefixes.txt">Eclipse Tycho</a></li> 042 * </ul> 043 */ 044public class PrefixTree extends Node { 045 public static final PrefixTree SENTINEL = new PrefixTree("sentinel"); 046 047 private static List<String> elementsOfPath(final String path) { 048 return Arrays.stream(path.split("/")).filter(e -> !e.isEmpty()).collect(toList()); 049 } 050 051 public PrefixTree(String name) { 052 super(name, false, null); 053 } 054 055 public int loadNodes(Stream<String> linesStream) { 056 AtomicInteger counter = new AtomicInteger(0); 057 linesStream.forEach(line -> { 058 if (loadNode(line)) { 059 counter.incrementAndGet(); 060 } 061 }); 062 return counter.get(); 063 } 064 065 public boolean loadNode(String line) { 066 if (!line.startsWith("#") && !line.trim().isEmpty()) { 067 Node currentNode = this; 068 for (String element : elementsOfPath(line)) { 069 currentNode = currentNode.addSibling(element, false, null); 070 } 071 return true; 072 } 073 return false; 074 } 075 076 public boolean acceptedPath(String path) { 077 final List<String> pathElements = elementsOfPath(path); 078 Node currentNode = this; 079 for (String pathElement : pathElements) { 080 currentNode = currentNode.getSibling(pathElement); 081 if (currentNode == null || currentNode.isLeaf()) { 082 break; 083 } 084 } 085 return currentNode != null && currentNode.isLeaf(); 086 } 087}