/* * 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 org.apache.aries.subsystem.core.archive; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.aries.subsystem.core.capabilityset.SimpleFilter; import org.osgi.framework.VersionRange; public abstract class AbstractClauseBasedHeader<C extends Clause> implements Header<C> { protected static VersionRange parseVersionRange(List<SimpleFilter> filters) { SimpleFilter floor = null; SimpleFilter ceiling = null; for (SimpleFilter filter : filters) { switch (filter.getOperation()) { case SimpleFilter.EQ: case SimpleFilter.GTE: floor = filter; break; case SimpleFilter.LTE: ceiling = filter; break; case SimpleFilter.NOT: SimpleFilter negated = ((List<SimpleFilter>)filter.getValue()).get(0); switch (negated.getOperation()) { case SimpleFilter.EQ: case SimpleFilter.GTE: ceiling = filter; break; case SimpleFilter.LTE: floor = filter; break; default: throw new IllegalArgumentException("Invalid filter: " + filter); } break; case SimpleFilter.PRESENT: /* This can happen with version ranges of the form * (1.5.0,2.0.0). The filter form will be * (&(version=*)(!(version<=1.5.0))(!(version>=2.0.0)). The * presence operator is required because an absent version * attribute would otherwise match. These should simply be * ignored for the purposes of converting back into a * version range. */ break; default: throw new IllegalArgumentException("Invalid filter: " + filter); } } if (ceiling == null) { return new VersionRange(String.valueOf(floor.getValue())); } String range = new StringBuilder() .append(floor.getOperation() == SimpleFilter.NOT ? '(' : '[') .append(floor.getOperation() == SimpleFilter.NOT ? ((List<SimpleFilter>)floor.getValue()).get(0).getValue() : floor.getValue()) .append(',') .append(ceiling.getOperation() == SimpleFilter.NOT ? ((List<SimpleFilter>)ceiling.getValue()).get(0).getValue() : ceiling.getValue()) .append(ceiling.getOperation() == SimpleFilter.NOT ? ')' : ']') .toString(); return new VersionRange(range); } private static <C> Collection<C> computeClauses(String header, ClauseFactory<C> factory) { Collection<String> clauseStrs = new ClauseTokenizer(header).getClauses(); Set<C> clauses = new HashSet<C>(clauseStrs.size()); for (String clause : clauseStrs) { clauses.add(factory.newInstance(clause)); } return clauses; } public interface ClauseFactory<C> { public C newInstance(String clause); } protected final Set<C> clauses; public AbstractClauseBasedHeader(Collection<C> clauses) { if (clauses.isEmpty()) { throw new IllegalArgumentException("No clauses"); } this.clauses = Collections.synchronizedSet(new HashSet<C>(clauses)); } public AbstractClauseBasedHeader(String header, ClauseFactory<C> factory) { this(computeClauses(header, factory)); } @Override public final Collection<C> getClauses() { return Collections.unmodifiableCollection(clauses); } @Override public int hashCode() { int result = 17; result = 31 * result + getName().hashCode(); result = 31 * result + clauses.hashCode(); return result; } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof AbstractClauseBasedHeader)) { return false; } AbstractClauseBasedHeader<?> that = (AbstractClauseBasedHeader<?>)o; return that.getName().equals(this.getName()) && that.clauses.equals(this.clauses); } @Override public String toString() { StringBuilder builder = new StringBuilder(); for (C clause : getClauses()) { builder.append(clause).append(','); } // Remove the trailing comma. Note at least one clause is guaranteed to // exist. builder.deleteCharAt(builder.length() - 1); return builder.toString(); } }