001package org.eclipse.aether.util.graph.version; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.util.Arrays; 023import java.util.Collection; 024 025import org.eclipse.aether.RepositoryException; 026import org.eclipse.aether.collection.DependencyCollectionContext; 027import org.eclipse.aether.collection.VersionFilter; 028 029/** 030 * A version filter that combines multiple version filters into a chain where each filter gets invoked one after the 031 * other, thereby accumulating their filtering effects. 032 */ 033public final class ChainedVersionFilter 034 implements VersionFilter 035{ 036 037 private final VersionFilter[] filters; 038 039 private int hashCode; 040 041 /** 042 * Chains the specified version filters. 043 * 044 * @param filter1 The first version filter, may be {@code null}. 045 * @param filter2 The second version filter, may be {@code null}. 046 * @return The chained version filter or {@code null} if both input filters are {@code null}. 047 */ 048 public static VersionFilter newInstance( VersionFilter filter1, VersionFilter filter2 ) 049 { 050 if ( filter1 == null ) 051 { 052 return filter2; 053 } 054 if ( filter2 == null ) 055 { 056 return filter1; 057 } 058 return new ChainedVersionFilter( new VersionFilter[] { filter1, filter2 } ); 059 } 060 061 /** 062 * Chains the specified version filters. 063 * 064 * @param filters The version filters to chain, must not be {@code null} or contain {@code null}. 065 * @return The chained version filter or {@code null} if the input array is empty. 066 */ 067 public static VersionFilter newInstance( VersionFilter... filters ) 068 { 069 if ( filters.length <= 1 ) 070 { 071 if ( filters.length <= 0 ) 072 { 073 return null; 074 } 075 return filters[0]; 076 } 077 return new ChainedVersionFilter( filters.clone() ); 078 } 079 080 /** 081 * Chains the specified version filters. 082 * 083 * @param filters The version filters to chain, must not be {@code null} or contain {@code null}. 084 * @return The chained version filter or {@code null} if the input collection is empty. 085 */ 086 public static VersionFilter newInstance( Collection<? extends VersionFilter> filters ) 087 { 088 if ( filters.size() <= 1 ) 089 { 090 if ( filters.isEmpty() ) 091 { 092 return null; 093 } 094 return filters.iterator().next(); 095 } 096 return new ChainedVersionFilter( filters.toArray( new VersionFilter[0] ) ); 097 } 098 099 private ChainedVersionFilter( VersionFilter[] filters ) 100 { 101 this.filters = filters; 102 } 103 104 public void filterVersions( VersionFilterContext context ) 105 throws RepositoryException 106 { 107 for ( int i = 0, n = filters.length; i < n && context.getCount() > 0; i++ ) 108 { 109 filters[i].filterVersions( context ); 110 } 111 } 112 113 public VersionFilter deriveChildFilter( DependencyCollectionContext context ) 114 { 115 VersionFilter[] children = null; 116 int removed = 0; 117 for ( int i = 0, n = filters.length; i < n; i++ ) 118 { 119 VersionFilter child = filters[i].deriveChildFilter( context ); 120 if ( children != null ) 121 { 122 children[i - removed] = child; 123 } 124 else if ( child != filters[i] ) 125 { 126 children = new VersionFilter[filters.length]; 127 System.arraycopy( filters, 0, children, 0, i ); 128 children[i - removed] = child; 129 } 130 if ( child == null ) 131 { 132 removed++; 133 } 134 } 135 if ( children == null ) 136 { 137 return this; 138 } 139 if ( removed > 0 ) 140 { 141 int count = filters.length - removed; 142 if ( count <= 0 ) 143 { 144 return null; 145 } 146 if ( count == 1 ) 147 { 148 return children[0]; 149 } 150 VersionFilter[] tmp = new VersionFilter[count]; 151 System.arraycopy( children, 0, tmp, 0, count ); 152 children = tmp; 153 } 154 return new ChainedVersionFilter( children ); 155 } 156 157 @Override 158 public boolean equals( Object obj ) 159 { 160 if ( this == obj ) 161 { 162 return true; 163 } 164 else if ( null == obj || !getClass().equals( obj.getClass() ) ) 165 { 166 return false; 167 } 168 169 ChainedVersionFilter that = (ChainedVersionFilter) obj; 170 return Arrays.equals( filters, that.filters ); 171 } 172 173 @Override 174 public int hashCode() 175 { 176 if ( hashCode == 0 ) 177 { 178 int hash = getClass().hashCode(); 179 hash = hash * 31 + Arrays.hashCode( filters ); 180 hashCode = hash; 181 } 182 return hashCode; 183 } 184 185}