소스 검색

Adding stream based asset utility

pull/60/head
Martin Stockhammer 4 년 전
부모
커밋
de22e846ed

archiva-modules/archiva-base/archiva-storage-api/src/main/java/org/apache/archiva/repository/storage/AssetSpliterator.java → archiva-modules/archiva-base/archiva-storage-api/src/main/java/org/apache/archiva/repository/storage/util/AssetSpliterator.java 파일 보기

@@ -1,3 +1,5 @@
package org.apache.archiva.repository.storage.util;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -16,7 +18,7 @@
* under the License.
*/

package org.apache.archiva.repository.storage;
import org.apache.archiva.repository.storage.StorageAsset;

import java.io.Closeable;
import java.util.Collections;
@@ -29,8 +31,6 @@ import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
*
@@ -39,7 +39,13 @@ import java.util.stream.StreamSupport;
* parents. If the spliterator is used in a parallel stream, there is no guarantee for
* the order of returned assets.
*
* The estimated size is not accurate, because the tree paths are scanned on demand.
* The estimated size is not accurate, because the tree paths are scanned on demand (lazy loaded)
*
* The spliterator returns the status of the assets at the time of retrieval. If modifications occur
* during traversal the returned assets may not represent the latest state.
* There is no check for modifications during traversal and no <code>{@link java.util.ConcurrentModificationException}</code> are thrown.
*
*
*
* @since 3.0
* @author Martin Stockhammer <martin_s@apache.org>
@@ -53,35 +59,45 @@ public class AssetSpliterator implements Spliterator<StorageAsset>, Closeable
private LinkedHashSet<StorageAsset> visitedContainers = new LinkedHashSet<>( );
private long visited = 0;
private final int splitThreshold;
private static final int CHARACTERISTICS = Spliterator.DISTINCT|Spliterator.NONNULL;
private static final int CHARACTERISTICS = Spliterator.DISTINCT|Spliterator.NONNULL|Spliterator.CONCURRENT;


AssetSpliterator( int splitThreshold, StorageAsset... assets) {
public AssetSpliterator( int splitThreshold, StorageAsset... assets) {
this.splitThreshold = splitThreshold;
init( assets );
}

private void init( StorageAsset[] assets )
{
if (assets.length==0 || assets[0] == null) {
throw new IllegalArgumentException( "There must be at least one non-null asset" );
}
Collections.addAll( this.workList, assets );
retrieveNextPath( this.workList.get( 0 ) );
}

AssetSpliterator( StorageAsset... assets) {
public AssetSpliterator( StorageAsset... assets) {
this.splitThreshold = DEFAULT_SPLIT_THRESHOLD;
Collections.addAll( this.workList, assets );
init( assets );
}

AssetSpliterator() {
protected AssetSpliterator() {
this.splitThreshold = DEFAULT_SPLIT_THRESHOLD;
}

AssetSpliterator( int splitThreshold) {
protected AssetSpliterator( int splitThreshold) {
this.splitThreshold = splitThreshold;
}


AssetSpliterator( int splitThreshold, Set<StorageAsset> visitedContainers) {
protected AssetSpliterator( int splitThreshold, Set<StorageAsset> visitedContainers) {
this.visitedContainers.addAll( visitedContainers );
this.splitThreshold = splitThreshold;
}

AssetSpliterator( List<StorageAsset> baseList, Set<StorageAsset> visitedContainers) {
protected AssetSpliterator( List<StorageAsset> baseList, Set<StorageAsset> visitedContainers) {
this.workList.addAll(baseList);
retrieveNextPath( this.workList.get( 0 ) );
this.visitedContainers.addAll( visitedContainers );
this.splitThreshold = DEFAULT_SPLIT_THRESHOLD;
}
@@ -150,7 +166,7 @@ public class AssetSpliterator implements Spliterator<StorageAsset>, Closeable
}
}

// In reverse order
// Assets are returned in reverse order
List<StorageAsset> getChildContainers( StorageAsset parent) {
final List<StorageAsset> children = parent.list( );
final int len = children.size( );
@@ -158,7 +174,7 @@ public class AssetSpliterator implements Spliterator<StorageAsset>, Closeable
children.get(len - i - 1)).filter( StorageAsset::isContainer ).collect( Collectors.toList( ) );
}

// In reverse order
// Assets are returned in reverse order
List<StorageAsset> getChildFiles(StorageAsset parent) {
final List<StorageAsset> children = parent.list( );
final int len = children.size( );
@@ -187,8 +203,8 @@ public class AssetSpliterator implements Spliterator<StorageAsset>, Closeable
//noinspection InfiniteLoopStatement
while (true)
{
newWorkList.add( workList.getFirst( ) );
newSpliterator.add( workList.getFirst( ) );
newWorkList.add( workList.removeFirst( ) );
newSpliterator.add( workList.removeFirst( ) );
}
} catch (NoSuchElementException e) {
//

+ 93
- 0
archiva-modules/archiva-base/archiva-storage-api/src/main/java/org/apache/archiva/repository/storage/util/StorageUtil.java 파일 보기

@@ -0,0 +1,93 @@
package org.apache.archiva.repository.storage.util;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import org.apache.archiva.repository.storage.StorageAsset;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
*
* Utility class for traversing the asset tree recursively and stream based access to the assets.
*
* @since 3.0
* @author Martin Stockhammer <martin_s@apache.org>
*/
public class StorageUtil
{
/**
* Walk the tree starting at the given asset. The consumer is called for each asset found.
* It runs a depth-first search where children are consumed before their parents.
*
* @param start the starting asset
* @param consumer the consumer that is applied to each asset
*/
public static void walk( StorageAsset start, Consumer<StorageAsset> consumer ) {
try(Stream<StorageAsset> assetStream = newAssetStream( start, false )) {
assetStream.forEach( consumer::accept );
}
}

/**
* Walk the tree starting at the given asset. The consumer function is called for each asset found
* as long as it returns <code>true</code> as result. If the function returns <code>false</code> the
* processing stops.
* It runs a depth-first search where children are consumed before their parents.
*
* @param start the starting asset
* @param consumer the consumer function that is applied to each asset and that has to return <code>true</code>,
* if the walk should continue.
*/
public static void walk( StorageAsset start, Function<StorageAsset, Boolean> consumer ) {
try(Stream<StorageAsset> assetStream = newAssetStream( start, false )) {
assetStream.anyMatch( a -> !consumer.apply( a ) );
}
}


/**
* Returns a stream of assets starting at the given start node. The returned stream returns a closable
* stream and should always be used in a try-with-resources statement.
*
* @param start the starting asset
* @param parallel <code>true</code>, if a parallel stream should be created, otherwise <code>false</code>
* @return the newly created stream
*/
public static Stream<StorageAsset> newAssetStream( StorageAsset start, boolean parallel )
{
return StreamSupport.stream( new AssetSpliterator( start ), parallel );
}


/**
* Returns a non-parallel stream.
* Calls {@link #newAssetStream(StorageAsset, boolean)} with <code>parallel=false</code>.
*
* @param start the starting asset
* @return the returned stream object
*/
public static Stream<StorageAsset> newAssetStream( StorageAsset start) {
return newAssetStream( start, false );
}


}

+ 0
- 100
archiva-modules/archiva-base/archiva-storage-api/src/test/java/org/apache/archiva/repository/storage/AssetSpliteratorTest.java 파일 보기

@@ -1,100 +0,0 @@
package org.apache.archiva.repository.storage;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import org.apache.archiva.repository.storage.mock.MockAsset;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
* Test the AssetSpliterator class
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
class AssetSpliteratorTest
{

private StorageAsset createTree() {
MockAsset root = new MockAsset( "" );
for (int i=0; i<10; i++) {
String name1 = "a" + String.format("%03d",i);
MockAsset parent1 = new MockAsset( root, name1 );
for (int k=0; k<15; k++) {
String name2 = name1 + String.format("%03d", k);
MockAsset parent2 = new MockAsset( parent1, name2 );
for (int u=0; u<5; u++) {
String name3 = name2 + String.format("%03d", u);
MockAsset parent3 = new MockAsset( parent2, name3 );
}
}
}
return root;
}

private class Status {
LinkedList<StorageAsset> visited = new LinkedList<>( );

Status() {

}

public void add(StorageAsset asset) {
visited.addLast( asset );
}

public StorageAsset getLast() {
return visited.getLast( );
}

public List<StorageAsset> getVisited() {
return visited;
}

public int size() {
return visited.size( );
}
}

@Test
void tryAdvance( )
{
StorageAsset root = createTree( );
AssetSpliterator spliterator = new AssetSpliterator( root );
final StorageAsset expectedTarget = root.list( ).get( 0 ).list( ).get( 0 ).list( ).get( 0 );
final Status status = new Status( );
spliterator.tryAdvance( a -> status.add( a ) );
assertEquals( expectedTarget, status.getLast( ) );
}

@Test
void forEachRemaining( )
{
}

@Test
void trySplit( )
{
}
}

+ 19
- 2
archiva-modules/archiva-base/archiva-storage-api/src/test/java/org/apache/archiva/repository/storage/mock/MockAsset.java 파일 보기

@@ -45,12 +45,12 @@ public class MockAsset implements StorageAsset

public MockAsset( String name ) {
this.name = name;
this.path = "";
this.path = "/";
}

public MockAsset( MockAsset parent, String name ) {
this.parent = parent;
this.path = parent.getPath( ) + "/" + name;
this.path = (parent.hasParent()?parent.getPath( ):"") + "/" + name;
this.name = name;
parent.registerChild( this );
}
@@ -189,4 +189,21 @@ public class MockAsset implements StorageAsset
{
return getPath();
}

@Override
public boolean equals( Object o )
{
if ( this == o ) return true;
if ( o == null || getClass( ) != o.getClass( ) ) return false;

MockAsset mockAsset = (MockAsset) o;

return path.equals( mockAsset.path );
}

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

+ 161
- 0
archiva-modules/archiva-base/archiva-storage-api/src/test/java/org/apache/archiva/repository/storage/util/AssetSpliteratorTest.java 파일 보기

@@ -0,0 +1,161 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.archiva.repository.storage.util;

import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.archiva.repository.storage.mock.MockAsset;
import org.junit.jupiter.api.Test;

import java.util.Spliterator;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
* Test the AssetSpliterator class
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
class AssetSpliteratorTest
{

private static int LEVEL1 = 10;
private static int LEVEL2 = 15;
private static int LEVEL3 = 5;



private StorageAsset createTree() {
return createTree( LEVEL1, LEVEL2, LEVEL3 );
}

private StorageAsset createTree(int... levelElements) {
MockAsset root = new MockAsset( "" );
recurseSubTree( root, 0, levelElements );
return root;
}

private void recurseSubTree(MockAsset parent, int level, int[] levelElements) {
if (level < levelElements.length)
{
for ( int k = 0; k < levelElements[level]; k++ )
{
String name = parent.getName( ) + String.format( "%03d", k );
MockAsset asset = new MockAsset( parent, name );
recurseSubTree( asset, level + 1, levelElements );
}
}
}

@Test
void tryAdvance( )
{
StorageAsset root = createTree( );
AssetSpliterator spliterator = new AssetSpliterator( root );
final ConsumeVisitStatus status = new ConsumeVisitStatus( );
StorageAsset expectedTarget = root.list( ).get( 0 ).list( ).get( 0 ).list( ).get( 0 );
spliterator.tryAdvance( status );
assertEquals( 1, status.size( ) );
assertEquals( expectedTarget, status.getLast( ) );

spliterator.tryAdvance( status );
assertEquals( 2, status.size( ) );
expectedTarget = root.list( ).get( 0 ).list( ).get( 0 ).list( ).get( 1 );
assertEquals( expectedTarget, status.getLast( ) );

}

@Test
void forEachRemaining( )
{
StorageAsset root = createTree( );
AssetSpliterator spliterator = new AssetSpliterator( root );
final ConsumeVisitStatus status = new ConsumeVisitStatus( );
spliterator.forEachRemaining( status );
// 10 * 15 * 5 + 10 * 15 + 10 + 1
assertEquals( LEVEL1*LEVEL2*LEVEL3+LEVEL1*LEVEL2+LEVEL1+1
, status.size( ) );
assertEquals( root, status.getLast( ) );
}

@Test
void forEachRemaining2( )
{
StorageAsset root = createTree( );
AssetSpliterator spliterator = new AssetSpliterator( root );
final ConsumeVisitStatus status = new ConsumeVisitStatus( );
spliterator.tryAdvance( a -> {} );
spliterator.tryAdvance( a -> {} );
spliterator.tryAdvance( a -> {} );
spliterator.tryAdvance( a -> {} );

spliterator.forEachRemaining( status );
int expected = LEVEL1 * LEVEL2 * LEVEL3 + LEVEL1 * LEVEL2 + LEVEL1 + 1;
expected = expected - 4;
assertEquals( expected
, status.size( ) );
assertEquals( root, status.getLast( ) );
}

@Test
void forEachRemaining3( )
{
StorageAsset root = createTree( );
StorageAsset testRoot = root.list( ).get( 1 );
AssetSpliterator spliterator = new AssetSpliterator( testRoot );
final ConsumeVisitStatus status = new ConsumeVisitStatus( );
spliterator.forEachRemaining( status );
int expected = LEVEL2 * LEVEL3 + LEVEL2 + 1;
assertEquals( expected
, status.size( ) );
assertEquals( testRoot, status.getLast( ) );
}


@Test
void trySplit( )
{
StorageAsset root = createTree( );
AssetSpliterator spliterator = new AssetSpliterator( root );
final ConsumeVisitStatus status1 = new ConsumeVisitStatus( );
final ConsumeVisitStatus status2 = new ConsumeVisitStatus( );
Spliterator<StorageAsset> newSpliterator = spliterator.trySplit( );
assertNotNull( newSpliterator );
newSpliterator.forEachRemaining( status1 );
spliterator.forEachRemaining( status2 );

int sum = LEVEL1 * LEVEL2 * LEVEL3 + LEVEL1 * LEVEL2 + LEVEL1 + 1;
int expected1 = sum / 2;
int expected2 = sum / 2 + 1 ;
assertEquals( expected1, status1.size( ) );
assertEquals( expected2, status2.size( ) );

}

@Test
void checkCharacteristics() {
StorageAsset root = createTree( );
AssetSpliterator spliterator = new AssetSpliterator( root );
assertEquals( Spliterator.NONNULL, spliterator.characteristics( ) & Spliterator.NONNULL );
assertEquals( Spliterator.CONCURRENT, spliterator.characteristics( ) & Spliterator.CONCURRENT );
assertEquals( Spliterator.DISTINCT, spliterator.characteristics( ) & Spliterator.DISTINCT );


}
}

+ 35
- 0
archiva-modules/archiva-base/archiva-storage-api/src/test/java/org/apache/archiva/repository/storage/util/ConsumeVisitStatus.java 파일 보기

@@ -0,0 +1,35 @@
package org.apache.archiva.repository.storage.util;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import org.apache.archiva.repository.storage.StorageAsset;

import java.util.function.Consumer;

/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
public class ConsumeVisitStatus extends VisitStatus implements Consumer<StorageAsset>
{
@Override
public void accept( StorageAsset asset )
{
add( asset );
}
}

+ 45
- 0
archiva-modules/archiva-base/archiva-storage-api/src/test/java/org/apache/archiva/repository/storage/util/StopVisitStatus.java 파일 보기

@@ -0,0 +1,45 @@
package org.apache.archiva.repository.storage.util;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import org.apache.archiva.repository.storage.StorageAsset;

import java.util.function.Function;
import java.util.function.Predicate;

/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
public class StopVisitStatus extends VisitStatus implements Function<StorageAsset, Boolean>
{
private Predicate<StorageAsset> stopCondition;

public void setStopCondition( Predicate<StorageAsset> predicate )
{
this.stopCondition = predicate;
}

@Override
public Boolean apply( StorageAsset asset )
{
add( asset );
return !stopCondition.test( asset );
}

}

+ 134
- 0
archiva-modules/archiva-base/archiva-storage-api/src/test/java/org/apache/archiva/repository/storage/util/StorageUtilTest.java 파일 보기

@@ -0,0 +1,134 @@
package org.apache.archiva.repository.storage.util;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/


import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.archiva.repository.storage.mock.MockAsset;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.*;

/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
class StorageUtilTest
{
private static int LEVEL1 = 12;
private static int LEVEL2 = 13;
private static int LEVEL3 = 6;



private StorageAsset createTree() {
return createTree( LEVEL1, LEVEL2, LEVEL3 );
}

private StorageAsset createTree(int... levelElements) {
MockAsset root = new MockAsset( "" );
recurseSubTree( root, 0, levelElements );
return root;
}

private void recurseSubTree(MockAsset parent, int level, int[] levelElements) {
if (level < levelElements.length)
{
for ( int k = 0; k < levelElements[level]; k++ )
{
String name = parent.getName( ) + String.format( "%03d", k );
MockAsset asset = new MockAsset( parent, name );
recurseSubTree( asset, level + 1, levelElements );
}
}
}

@Test
void testWalkFromRoot() {
StorageAsset root = createTree( );
ConsumeVisitStatus status = new ConsumeVisitStatus( );

StorageUtil.walk( root, status );
int expected = LEVEL1 * LEVEL2 * LEVEL3 + LEVEL1 * LEVEL2 + LEVEL1 + 1;
assertEquals( expected, status.size() );
StorageAsset first = root.list( ).get( 0 ).list( ).get( 0 ).list().get(0);
assertEquals( first, status.getFirst( ) );
assertEquals( root, status.getLast( ) );
}

@Test
void testWalkFromChild() {
StorageAsset root = createTree( );
ConsumeVisitStatus status = new ConsumeVisitStatus( );
StorageAsset testRoot = root.list( ).get( 3 );

StorageUtil.walk( testRoot, status );
int expected = LEVEL2 * LEVEL3 + LEVEL2 + 1;
assertEquals( expected, status.size() );
StorageAsset first = root.list( ).get( 3 ).list( ).get( 0 ).list().get(0);
assertEquals( first, status.getFirst( ) );
assertEquals( testRoot, status.getLast( ) );
}


@Test
void testWalkFromRootWithCondition() {
StorageAsset root = createTree( );
StopVisitStatus status = new StopVisitStatus( );
status.setStopCondition( a -> a.getName().equals("001002003") );

StorageUtil.walk( root, status );
assertEquals( "001002003", status.getLast( ).getName() );
int expected = LEVEL2 * LEVEL3 + LEVEL2 + 2 * LEVEL3 + 1 + 1 + 1 + 4;
assertEquals( expected, status.size() );
}

@Test
void testStream() {
StorageAsset root = createTree( );
ConsumeVisitStatus status = new ConsumeVisitStatus( );

List<StorageAsset> result;
try ( Stream<StorageAsset> stream = StorageUtil.newAssetStream( root, false ) )
{
result = stream.filter( a -> a.getName( ).startsWith( "001" ) ).collect( Collectors.toList());
}
int expected = LEVEL2 * LEVEL3 + LEVEL2 + 1;
assertEquals( expected, result.size( ) );
assertEquals( "001", result.get( result.size( ) - 1 ).getName() );
assertEquals( "001012", result.get( result.size( ) - 2 ).getName() );
}

@Test
void testStreamParallel() {
StorageAsset root = createTree( );
ConsumeVisitStatus status = new ConsumeVisitStatus( );

List<StorageAsset> result;
try ( Stream<StorageAsset> stream = StorageUtil.newAssetStream( root, true ) )
{
result = stream.filter( a -> a.getName( ).startsWith( "001" ) ).collect( Collectors.toList());
}
int expected = LEVEL2 * LEVEL3 + LEVEL2 + 1;
assertEquals( expected, result.size( ) );
}
}

+ 67
- 0
archiva-modules/archiva-base/archiva-storage-api/src/test/java/org/apache/archiva/repository/storage/util/VisitStatus.java 파일 보기

@@ -0,0 +1,67 @@
package org.apache.archiva.repository.storage.util;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import org.apache.archiva.repository.storage.StorageAsset;

import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
class VisitStatus
{
LinkedList<StorageAsset> visited = new LinkedList<>( );

VisitStatus( )
{

}

public void add( StorageAsset asset )
{
// System.out.println( "Adding " + asset.getPath( ) );
visited.addLast( asset );
}

public StorageAsset getLast( )
{
return visited.getLast( );
}

public StorageAsset getFirst() {
return visited.getFirst( );
}

public List<StorageAsset> getVisited( )
{
return visited;
}

public int size( )
{
return visited.size( );
}


}

Loading…
취소
저장