/*
* 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.karaf.features.internal.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.karaf.features.internal.resolver.CapabilitySet;
import org.apache.karaf.features.internal.resolver.SimpleFilter;
import org.osgi.framework.Constants;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
public final class RequirementSort<T extends Resource> {
private RequirementSort() {
}
/**
* Sort {@link Resource} based on their {@link Requirement}s and {@link Capability}s.
*
* @param resources the resource to sort.
* @param <T> the resources type.
* @return sorted collection of resources.
*/
public static <T extends Resource> Collection<T> sort(Collection<T> resources) {
Set<String> namespaces = new HashSet<String>();
for (Resource r : resources) {
for (Capability cap : r.getCapabilities(null)) {
namespaces.add(cap.getNamespace());
}
}
CapabilitySet capSet = new CapabilitySet(new ArrayList<String>(namespaces));
for (Resource r : resources) {
for (Capability cap : r.getCapabilities(null)) {
capSet.addCapability(cap);
}
}
Set<T> sorted = new LinkedHashSet<T>();
Set<T> visited = new LinkedHashSet<T>();
for (T r : resources) {
visit(r, visited, sorted, capSet);
}
return sorted;
}
private static <T extends Resource> void visit(T resource, Set<T> visited, Set<T> sorted, CapabilitySet capSet) {
if (!visited.add(resource)) {
return;
}
for (T r : collectDependencies(resource, capSet)) {
visit(r, visited, sorted, capSet);
}
sorted.add(resource);
}
@SuppressWarnings("unchecked")
private static <T extends Resource> Set<T> collectDependencies(T resource, CapabilitySet capSet) {
Set<T> result = new LinkedHashSet<T>();
for (Requirement requirement : resource.getRequirements(null)) {
String filter = requirement.getDirectives().get(Constants.FILTER_DIRECTIVE);
SimpleFilter sf = (filter != null)
? SimpleFilter.parse(filter)
: new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
for (Capability cap : capSet.match(sf, true)) {
result.add((T) cap.getResource());
}
}
return result;
}
}